fortran - 如何在 Fortran 中获取派生类型组件的编号、名称和值

标签 fortran fortran95

我是 Fortran 新手。我想开发一个子例程,它将分配的变量信息打印到 Fortran 95 中的大型派生类型。为了简化,假设我们有一个派生类型声明和分配,如下所示:

type SubjectType
    character(20) :: genre
    character(20) :: maindude
end type SubjectType

type BookType
    character(20) :: title
    character(20) :: author
    type(SubjectType) :: subject 

end type Booktype

type(Booktype) :: Book

Book%title = "Harry Potter"
Book%author = "JK Rowling"
Book%subject%genre = "Fantasy"
Book%subject%maindude = "Ron Weasley"

我希望程序的输出是一个文本文件,如下所示:

Book%title, Harry Potter

Book%author, JK Rowling

Book%subject%genre, Fantasy

Book%subject%maindude, Ron Weasley

为了实现这一目标,我相信这就是我需要做的:

  • 确定每个级别的派生类型中的字段数。例如,Booktype 中的字段数量为 3。Booktype%SubjectType 中的字段数量为 2。
  • 找到一种方法将字段“number”与字段名称相关联(也许使用指针?)
  • 循环所有字段编号并获取它们的名称和值。

我的问题是双重的。首先我的方法是否正确/会带来预期的结果吗?第二步 如何完成此过程的步骤 1。即如何获取每个级别的派生类型中的字段数量?

最佳答案

我没有像问题中提出的那样通过索引号来识别数据类型/字段,而是采用了一个非常基本的“键/值容器”类1来完成任务。这个想法是使用几个足够通用的派生类型,可以重复使用来创建任意数量的数据字段来表示各种图书信息,并且您可以轻松访问(和/或打印)。

! Start off with a generic DT to represent character string data fields.
type :: Field
    character(len=:), allocatable :: type  !<- A category such as 'book'
    character(len=:), allocatable :: key   !<- Such as 'title' or 'author'
    character(len=:), allocatable :: val   !<- Such as 'Harry Potter' or 'JK Rowling'
end type

! It is simplest to create/use multiple Fields directly in the BookType.
type :: BookType
    character(len=8) :: type = 'BookType'
    type(Field), dimension(:), allocatable :: fields
    integer :: size = 0
    contains
        procedure, pass :: valueFromKey
end type

! Create a container to hold each BookType created.
type :: BookCollection
    type(BookType), dimension(:), allocatable :: book
end type

我将提供函数 valueFromKey 作为示例,说明如何返回与给定键对应的值。

function valueFromKey(self, key) 
    implicit none
    class(BookType) :: self
    character(*), intent(in) :: key
    character(len=:), allocatable :: valueFromKey
    integer :: i
    logical :: val_is_found

    val_is_found = .False.
    do i = 1,self%size 
        if (trim(key) == self%fields(i)%key) then
            valueFromKey = self%fields(i)%val
            val_is_found = .True.
            exit
        endif
    enddo

    if (.not. val_is_found) then
        valueFromKey = "None"
    endif
end function valueFromKey

将以上所有代码放在一个模块中。我省略了一些辅助函数,因为它们不需要回答问题并提供有效的解决方案。不过,您将在下面的示例程序中看到其中之一 (newBook)。请注意,字段上的循环会打印所有现有数据,这些数据可能因书而异。另外,请求 valueFromKey 获取任何不在图书数据中的键将返回字符串“None”。

! Example usage:
program main
    use BookModule
    implicit none
    integer :: i, j
    character(len=6) :: num
    type(BookCollection) :: MyBooks

    allocate(MyBooks%book(2))
    MyBooks%book(1) = newBook(keys=['title', 'author', 'date', 'genre', 'lead'], values=["Harry Potter", "JK Rowling", "1997", "Fantasy", "Ron Weasley"])
    MyBooks%book(2) = newBook(keys=['title', 'author', 'lead'], values=["1984", "George Orwell", "Winston Smith"])

    print *, "LOOP OVER BOOK COLLECTION"
    do i = 1, size(MyBooks%book)
        write(num, '(i6)') i
        print *, "Item ", adjustl(num)
        do j = 1, MyBooks%book(i)%size 
            print *, MyBooks%book(i)%type, ", ", MyBooks%book(i)%fields(j)%type, ", ", MyBooks%book(i)%fields(j)%key, ", ", MyBooks%book(i)%fields(j)%val
        enddo
        print *
    enddo

    print *, "GET FIELD VALUE FROM KEY"
    print *, " Title:  ", MyBooks%book(1)%valueFromKey('title')
    print *, " Author: ", MyBooks%book(1)%valueFromKey('author')
    print *, " Date:   ", MyBooks%book(1)%valueFromKey('date')
    print *
    print *, " Title:  ", MyBooks%book(2)%valueFromKey('title')
    print *, " Author: ", MyBooks%book(2)%valueFromKey('author')
    print *, " Date:   ", MyBooks%book(2)%valueFromKey('date')
end program main

示例输出:

 LOOP OVER BOOK COLLECTION
 Item 1
 BookType, book, title, Harry Potter
 BookType, book, author, JK Rowling
 BookType, book, date, 1997
 BookType, subject, genre, Fantasy
 BookType, subject, lead, Ron Weasley

 Item 2
 BookType, book, title, 1984
 BookType, book, author, George Orwell
 BookType, subject, lead, Winston Smith

 GET FIELD VALUE FROM KEY
  Title:  Harry Potter
  Author: JK Rowling
  Date:   1997

  Title:  1984
  Author: George Orwell
  Date:   None

1 这里提到的基本“键/值容器”类缺乏任何哈希/映射/字典之类的功能;查找仅通过循环数据成员直到找到键,然后获取相应的值来工作。它实际上只适用于中小型数据集。

关于fortran - 如何在 Fortran 中获取派生类型组件的编号、名称和值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44652676/

相关文章:

c++ - 从静态库函数访问文本数据文件

fortran - 为什么SCons构建的成功取决于variant_dir名称?

pointers - Fortran 指针算术

grid - 算法[最好是fortran]从二维非结构化网格中插入数据以形成笛卡尔网格

gfortran - 如果填充值不等于某些值,则将填充值分配给变量

python - 当前用 Python 包装现代 Fortran 代码的最佳方法

python - 段错误: 11 - running fortran wrapped in python

nested - Fortran 嵌套 WHERE 语句

c - 在 Doxygen 中记录没有扩展名的文件

fortran - 可以在没有任何长度规范的情况下声明 Fortran 中的多字符常量吗?