我喜欢有一个列表,就像在 Python 中一样,但对于 Fortran。我知道有一个通用列表类型。但是在这里我必须为列表中的每个数据定义一个类型,例如一个用于 Real*8,一个用于 Complex*16,Dimension(:,:) 等等。我想将数据放入不需要定义维度的列表中,如果它是 Real、Complex 或 Integer - 就像 Python 中的列表一样,我可以将我想要的所有内容放入其中。那可能吗?Fortran 是否已经存在这样的列表?
Python 类似于 Fortran 中的通用列表
免责声明:我是链接模块的作者。
首先,我建议在 Stackoverflow 上发布这个问题,许多 Fortran 专家在那里会面。
有更多可能的方法来解决这个问题。一种类似于 C void 指针(使用transfer)或更安全的一种使用class(*). 两者理论上都允许异构列表。然后,您有责任正确检索不同类型的项目。在这种class(*)情况下,它是使用select type构造安全地完成的。
然后是使用类似于 C++ 模板的参数多态性的方法,但使用预处理器和include. 恕我直言,它们更易于使用,但只有一种类型的项目可以在列表的副本中。您可以为所需的每种类型制作单独的副本。
您可以在https://github.com/LadaF/fortran-list找到两者的示例模块 。我并不声称它是完美的,但它适合我的需要并且我经常使用它。
- - 编辑 - - -
如果您不喜欢链表,因为您需要随机访问,并且您可以忍受更困难的追加和更困难的插入和删除,请使用这种简单派生类型的 Fortran 数组:
module array_list
type container
class(*), allocatable :: item
class(*), allocatable :: items(:)
end type
interface add_item
module procedure add_item_scalar
module procedure add_item_array
end interface
contains
subroutine add_item_scalar(a, e)
type(container),allocatable,intent(inout) :: a(:)
class(*),intent(in) :: e
type(container),allocatable :: tmp(:)
if (.not.allocated(a)) then
allocate(a(1))
allocate(a(1)%item, source = e)
else
call move_alloc(a,tmp)
allocate(a(size(tmp)+1))
a(1:size(tmp)) = tmp
allocate(a(size(tmp)+1)%item, source = e)
end if
end subroutine
subroutine add_item_array(a, e)
type(container),allocatable,intent(inout) :: a(:)
class(*),intent(in) :: e(:)
type(container),allocatable :: tmp(:)
if (.not.allocated(a)) then
allocate(a(1))
allocate(a(1)%items(size(e)), source = e)
else
call move_alloc(a,tmp)
allocate(a(size(tmp)+1))
a(1:size(tmp)) = tmp
allocate(a(size(tmp)+1)%items(size(e)), source = e)
end if
end subroutine
end module
use array_list
type(container), allocatable :: a_list(:)
type newtype
end type
integer i
call add_item(a_list, 1)
call add_item(a_list, 5.5)
call add_item(a_list, (4., 5.))
call add_item(a_list, newtype())
call add_item(a_list, [1, 2, 3, 4, 5])
do i = 1, size(a_list)
call print(a_list(i))
end do
contains
subroutine print(c)
type(container), intent(in) :: c
if (allocated(c%item)) then
select type (x=>c%item)
type is (integer)
print *, x
type is (real)
print *, x
type is (complex)
print *, x
type is (newtype)
print *, "is newtype"
class default
print *, "is unknown type"
end select
else if (allocated(c%items)) then
select type (x=>c%items)
type is (integer)
print *, x
type is (real)
print *, x
type is (complex)
print *, x
type is (newtype)
print *, "is array of newtype"
class default
print *, "is array of unknown type"
end select
else
write(*,*) "Error, empty container"
end if
end subroutine
end
编译运行
> sunf90 alist.f90
> ./a.out
1
5.5
(4.0,5.0)
is newtype
1 2 3 4 5
这个答案更多的是评论;我的评论对于评论来说太长了,并且具有其他格式选项将很有用。
我知道有一个通用列表类型。
快速浏览您引用的链接描述了用于链表的 Fortran 模块。Python中列表的随机访问(即查找存储在任意索引处的元素)是; 对于长度的链表,随机访问是,因为要查看th 元素,你必须从列表的头部开始,并遍历要到达的元素(列表的链接)元素。数据结构不同。
我想将数据放入不需要定义维度的列表中,如果它是 Real、Complex 或 Integer - 就像 Python 中的列表一样,我可以将我想要的所有内容放入其中。那可能吗?
是的。Fortran 是一种图灵完备的语言,您的建议是模拟 Python(也是图灵完备的语言)的特性,因此可以定义 Fortran“列表”数据类型。
实现“列表”数据类型的一种可能方法是使用三个数组:
- 第一个数组本质上是数据存储;您可以使用该
transfer函数将数据转换为通用表示,例如字符数组(此策略或多或少模拟 Fortran 中的 C 样式 void 指针,请参阅此博客文章) - 第二个数组存储您存储在列表中的每个对象的索引偏移量
- 第三个数组以某种方式存储每个对象的类型信息;对于内置类型,此步骤可能很容易,但 Fortran 90 允许您定义复合类型(有点像结构),并且为复合类型存储信息可能需要更复杂的方案或更多辅助数据结构。
我并不是说这种方案是最好的方法——它可能不是,因为这是我脑海中浮现的第一个想法。我偏向于在 Fortran 中使用指针,因为我学习了 Fortran 90 的 Fortran 77 偏向风格,但在这里可以使用 Fortran 指针来产生很好的效果。如果我在 C 中实现它,我绝对会使用指针,因为指针对于 C 习语来说是必不可少的。
我猜想大多数模拟“列表”数据类型的方法都将涉及巧妙的数据编码和检索方案,以及一个很好的界面来隐藏它。
您可能会发现查看 Python 列表数据类型的 C 实现的描述(如此博客文章、源代码或此 Stack Overflow 问题的答案)很有帮助。
Fortran 是否已经存在这样的列表?
我无法通过快速搜索找到一个。
我喜欢有一个列表,就像在 Python 中一样,但对于 Fortran。
为什么?你的用例是什么?如果您事先知道要存储的数据类型,那么使用具有已知数据类型的数组会更容易,并且可以节省您的工作、麻烦和可能的执行时间(存储任意对象需要一些间接和额外的内存引用) . 此外,使用标准数组数据结构更符合 Fortran 的习惯(尽管,是的,人们可以并且确实使用数组来模拟其他数据结构);数据结构转换在其他语言(C 风格的语言、Lisp、Python、Ruby 等解释语言等)中更具特色。