Как получить число, имена и значения компонентов производного типа в Фортране
Я новичок в Фортране. Я хотел бы разработать подпрограмму, которая печатает назначенную переменную информацию для большого производного типа в 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"
Я хотел бы, чтобы вывод моей программы был текстовым файлом следующим образом:
Книга% title, Гарри Поттер
Автор книги%, Джоан Роулинг
Книга% тема% жанр, фэнтези
Книга% предмет% maindude, Рон Уизли
Чтобы добиться этого, я считаю, что это то, что мне нужно сделать:
- Определите количество полей в производном типе на каждом уровне. Например, количество полей в
Booktype
будет 3. Количество полей вBooktype%SubjectType
будет 2. - Найдите способ связать поле "число" с именем поля (возможно, с помощью указателей?)
- переберите все номера полей и получите их имена и значения.
Мой вопрос здесь двоякий. Во-первых, правильный ли мой подход / приведет ли он к намеченному результату? Второй Как мне выполнить шаг 1 этой процедуры. А именно, как я могу получить количество полей в производном типе на каждом уровне?
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 Базовому классу "ключ / контейнер значений", упомянутому здесь, не хватает какой-либо хеш-функции / функции отображения словаря; поиск работает только путем циклического перебора членов данных до тех пор, пока ключ не будет найден, а затем получения соответствующего значения. Это действительно подходит только для небольших и средних наборов данных.