Как получить количество, имена и значения компонентов производного типа в 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"

Я хотел бы, чтобы вывод моей программы был текстовым файлом следующим образом:

Книга%название, Гарри Поттер

Книга%автор, Джоан Роулинг

Книга%тематика%жанр, Фэнтези

Книга%subject%maindude, Рон Уизли

Чтобы добиться этого, я считаю, что мне нужно сделать следующее:

  • Определите количество полей в производном типе на каждом уровне. Например, количество полей в Booktype будет равно 3. Количество полей в Booktype%SubjectType будет равно 2.
  • Найдите способ связать поле «номер» с именем поля (возможно, с помощью указателей?)
  • перебрать все номера полей и получить их имена и значения.

Мой вопрос здесь двоякий. Во-первых, правильный ли мой подход/приведет ли он к ожидаемому результату? Второй Как выполнить шаг 1 этой процедуры. А именно, как мне получить количество полей в производном типе на каждом уровне?


person user32882    schedule 20.06.2017    source источник
comment
Используйте ввод/вывод производного типа (DTIO) -Fortran 2003-.   -  person M. Chinoune    schedule 20.06.2017
comment
Не идите по этому пути, не относитесь к производному типу как к массиву, это дорога в ад.   -  person Vladimir F    schedule 20.06.2017


Ответы (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) используется в примере программы ниже. Обратите внимание, что цикл по полям печатает все существующие данные, которые могут варьироваться от книги к книге. OTH, запрос valueFromKey для любого ключа, отсутствующего в данных книги, вернет строку «Нет».

! 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 Упомянутый здесь базовый класс "контейнер ключей/значений" не имеет каких-либо функций, подобных хешированию/отображению/словарю; поиск работает только путем циклического перебора элементов данных до тех пор, пока не будет найден ключ, а затем захвата соответствующего значения. Это действительно подходит только для наборов данных малого и среднего размера.

person Matt P    schedule 22.06.2017