如何使用名称列表在派生类型中编写可分配数组?
How to write an allocatable array in a derived type using namelists?
我在使用名称列表编写嵌套在派生类型中的可分配数组时遇到问题。下面显示了一个最小的示例。我如何修改程序以使派生类型中的可分配数组像未嵌套一样工作?
program test
implicit none
type struct_foo
integer, allocatable :: nested_bar(:)
end type struct_foo
integer, allocatable :: bar(:)
type(struct_foo) :: foo
! namelist / list / foo, bar
namelist / list / bar
allocate(bar(5))
bar = [1:5]
allocate(foo%nested_bar(5))
foo%nested_bar=[1:5]
write(*,list)
end program test
将 foo 从名单中注释掉后,它工作正常,产生输出:
&LIST
BAR = 1, 2, 3, 4, 5
/
由于包含 foo,程序编译失败:
>> ifort -traceback test_1.f90 -o test && ./test
test_1.f90(20): error #5498: Allocatable or pointer derived-type fields require a user-defined I/O procedure.
write(*,list)
--------^
compilation aborted for test_1.f90 (code 1)
如错误消息所述,您需要提供用户定义的派生类型 I/O (UDDTIO) 过程。对于具有可分配或指针组件的任何对象 input/output,这是必需的。
派生类型的对象在文件中如何格式化完全由UDDTIO程序控制。
下面是一个使用非常简单的输出格式的示例。通常,实现名单输出的 UDDTIO 过程会使用与名单输出的其他方面一致的输出格式,并且通常还会有一个相应的 UDDTIO 过程,该过程然后能够读回格式化的结果。
module foo_mod
implicit none
type struct_foo
integer, allocatable :: nested_bar(:)
contains
procedure, private :: write_formatted
generic :: write(formatted) => write_formatted
end type struct_foo
contains
subroutine write_formatted(dtv, unit, iotype, v_list, iostat, iomsg)
class(struct_foo), intent(in) :: dtv
integer, intent(in) :: unit
character(*), intent(in) :: iotype
integer, intent(in) :: v_list(:)
integer, intent(out) :: iostat
character(*), intent(inout) :: iomsg
integer :: i
if (allocated(dtv%nested_bar)) then
write (unit, "(l1,i10,i10)", iostat=iostat, iomsg=iomsg) &
.true., &
lbound(dtv%nested_bar, 1), &
ubound(dtv%nested_bar, 1)
if (iostat /= 0) return
do i = 1, size(dtv%nested_bar)
write (unit, "(i10)", iostat=iostat, iomsg=iomsg) &
dtv%nested_bar(i)
if (iostat /= 0) return
end do
write (unit, "(/)", iostat=iostat, iomsg=iomsg)
else
write (unit, "(l1,/)", iostat=iostat, iomsg=iomsg) .false.
end if
end subroutine write_formatted
end module foo_mod
program test
use foo_mod
implicit none
integer, allocatable :: bar(:)
type(struct_foo) :: foo
namelist / list / foo, bar
allocate(bar(5))
bar = [1:5]
allocate(foo%nested_bar(5))
foo%nested_bar=[1:5]
write (*,list)
end program test
UDDTIO 的使用显然需要一个实现此 Fortran 2003 语言功能的编译器。
我在使用名称列表编写嵌套在派生类型中的可分配数组时遇到问题。下面显示了一个最小的示例。我如何修改程序以使派生类型中的可分配数组像未嵌套一样工作?
program test
implicit none
type struct_foo
integer, allocatable :: nested_bar(:)
end type struct_foo
integer, allocatable :: bar(:)
type(struct_foo) :: foo
! namelist / list / foo, bar
namelist / list / bar
allocate(bar(5))
bar = [1:5]
allocate(foo%nested_bar(5))
foo%nested_bar=[1:5]
write(*,list)
end program test
将 foo 从名单中注释掉后,它工作正常,产生输出:
&LIST
BAR = 1, 2, 3, 4, 5
/
由于包含 foo,程序编译失败:
>> ifort -traceback test_1.f90 -o test && ./test
test_1.f90(20): error #5498: Allocatable or pointer derived-type fields require a user-defined I/O procedure.
write(*,list)
--------^
compilation aborted for test_1.f90 (code 1)
如错误消息所述,您需要提供用户定义的派生类型 I/O (UDDTIO) 过程。对于具有可分配或指针组件的任何对象 input/output,这是必需的。
派生类型的对象在文件中如何格式化完全由UDDTIO程序控制。
下面是一个使用非常简单的输出格式的示例。通常,实现名单输出的 UDDTIO 过程会使用与名单输出的其他方面一致的输出格式,并且通常还会有一个相应的 UDDTIO 过程,该过程然后能够读回格式化的结果。
module foo_mod
implicit none
type struct_foo
integer, allocatable :: nested_bar(:)
contains
procedure, private :: write_formatted
generic :: write(formatted) => write_formatted
end type struct_foo
contains
subroutine write_formatted(dtv, unit, iotype, v_list, iostat, iomsg)
class(struct_foo), intent(in) :: dtv
integer, intent(in) :: unit
character(*), intent(in) :: iotype
integer, intent(in) :: v_list(:)
integer, intent(out) :: iostat
character(*), intent(inout) :: iomsg
integer :: i
if (allocated(dtv%nested_bar)) then
write (unit, "(l1,i10,i10)", iostat=iostat, iomsg=iomsg) &
.true., &
lbound(dtv%nested_bar, 1), &
ubound(dtv%nested_bar, 1)
if (iostat /= 0) return
do i = 1, size(dtv%nested_bar)
write (unit, "(i10)", iostat=iostat, iomsg=iomsg) &
dtv%nested_bar(i)
if (iostat /= 0) return
end do
write (unit, "(/)", iostat=iostat, iomsg=iomsg)
else
write (unit, "(l1,/)", iostat=iostat, iomsg=iomsg) .false.
end if
end subroutine write_formatted
end module foo_mod
program test
use foo_mod
implicit none
integer, allocatable :: bar(:)
type(struct_foo) :: foo
namelist / list / foo, bar
allocate(bar(5))
bar = [1:5]
allocate(foo%nested_bar(5))
foo%nested_bar=[1:5]
write (*,list)
end program test
UDDTIO 的使用显然需要一个实现此 Fortran 2003 语言功能的编译器。