【问题标题】:How to use types in submodules Fortran如何在子模块 Fortran 中使用类型
【发布时间】:2019-03-06 12:18:44
【问题描述】:

我有一个基本模块,它定义了一些子例程(sub1sub2sub3)。然后,我想在一系列子模块中覆盖这些子例程。

我知道如何使用单独的模块和延迟类型来做到这一点,但我决定尝试使用 子模块。不幸的是,我不明白它们的用法。

这是我目前所拥有的:

基础模块

module BaseModule
    implicit none

    interface
        subroutine sub1(idx)
            implicit none
            integer, intent(in) :: idx
        end subroutine sub1

        subroutine sub2(idx)
            implicit none
            integer, intent(in) :: idx
        end subroutine sub2

        subroutine sub3(idx)
            implicit none
            integer, intent(in) :: idx
        end subroutine sub3    
    end interface
end module BaseModule

ChildModule1

submodule (BaseModule) ChildModule1
    implicit none

    type :: Child1
    contains
        module procedure :: sub1
        module procedure :: sub2
    end type

contains

    module subroutine sub1
        print*, "Child 1 - execute 'sub1' - idx = ", idx
    end subroutine sub1

    module subroutine sub2
        print*, "Child 1 - execute 'sub2' - idx = ", idx
    end subroutine sub2

end submodule ChildModule1

ChildModule2

submodule (BaseModule) ChildModule2
    implicit none

    type :: Child2
    contains
        module procedure :: sub1
        module procedure :: sub2
        module procedure :: sub3
    end type

contains

    module subroutine sub1
        print*, "Child 2 - execute 'sub1' - idx = ", idx
    end subroutine sub1

    module subroutine sub2
        print*, "Child 2 - execute 'sub2' - idx = ", idx
    end subroutine sub2

    module subroutine sub3
        print*, "Child 2 - execute 'sub3' - idx = ", idx
    end subroutine sub3

end submodule ChildModule2

测试

program test
    use ChildModule1
    use Childmodule2
    implicit none

    integer      :: idx
    type(Child1) :: c1
    type(Child2) :: c2

    do idx = 1, 10

        !! Child1 outputs
        call c1%sub1(idx)
        call c1%sub2(idx)

        !! Child2 outputs
        call c1%sub1(idx)
        call c2%sub2(idx)
        call c1%sub3(idx)
    end do

end program test

我对 submodules 的想法是我不必再次声明所有 inouts,但如果我想使用相同的子例程(例如 @ 987654329@) 在我声明不同类型的更多子模块中?现在我得到编译错误:

Error: MODULE PROCEDURE at (1) must be in a generic module interface

【问题讨论】:

  • 我真的不明白你的实际问题是什么。帖子中有一句话带问号,但它是相当开放的,我认为它确实需要一些例子,你想要什么,你遇到了什么问题。请注意,子模块是一个相当新的功能,我还没有将它们用于实际编程。大多数 OOP 可以在没有它们的情况下完成。
  • 感谢您的回答!我已经更新了我的问题,希望它现在更有意义!
  • 也许您对什么是子模块及其工作方式有误解。请参考this answer

标签: oop module fortran


【解决方案1】:

我会尝试澄清一些我认为您对 Fortran 中的 子模块 机制的误解。

然后,我想在一系列子模块中覆盖这些子例程。

您不会用子模块覆盖过程,而是实现它们。

我对 submodules 的想法是我不必再次声明所有 inouts

如果 inouts 是指过程的声明和签名(接口),那么是的,您不需要(但可以)在子模块中重复它们,但是,这不是子模块的目的。

但是如果我想在声明不同类型的多个子模块中使用相同的子例程(例如sub1)怎么办?

好吧,也许我必须简要解释一下子模块是什么,不是什么。有关更多详细信息,请参阅@SteveLionel 编写的this good article,或Fortran wiki 上的this entry,或您的compiler's reference(不管它是什么),甚至是您最喜欢的Modern Fortran 书籍.

正如我在another question 中所说,子模块是添加到语言中的一项功能,用于解决一个特定问题:接口和实现的分离。主要动机是当您只需要更改模块中的实现细节时生成的编译级联。

子模块可以通过主机关联访问父模块上的实体,但父模块不知道该子模块的存在。当您在子模块ChildModule1 中声明类型Child1 时,它只能在该子模块本身内部访问,而不能在父模块BaseModule 中访问。

此外,ChildModule1 不是一个模块,并且不能像您想要做的那样在主程序或任何其他程序单元中成为used。子模块的唯一作用是实现其父模块中缺少实现的module procedures

总结:以模块化、合理的方式布置你的源文件和程序单元,并使用子模块如果有意义让你的程序的实现独立于它们的声明(类似于@ 987654332@ 头文件和源文件......但将此比较与一粒盐)。


编辑:

我想你可能会认为 Fortran 中的 modulesubmodule 与其他语言中的类和子类有关。 他们没有!也许这是一个常见的误解,我不知道。

Fortran 具有用户定义的类型。它们可以绑定方法、构造函数和析构函数,可以封装数据,可以扩展,可以动态调度,可以声明为抽象,可以延迟和覆盖成员。这相当于其他语言的类。您可以(这是一种很好的做法)将每种类型和相关的东西分离到其对应的模块中。同样,您可以根据需要为每个扩展类型设置一个模块。

但是,子模块与此无关。

【讨论】:

  • 感谢您的详细解答!我查看了它们的链接,实际上我对子模块的真正含义有完全不同的想法。实际上,除了重新编译改进之外,我不明白为什么还要拥有它们。我有一种感觉,Fortran 以某种方式试图成为 OOP,但却让它变得难以置信的困难,有时甚至毫无意义。大多数科学程序都是用 Fortran 编写的,在我看来,这是该语言仍然存在的唯一原因。我显然不能代表所有人,但至少在我的研究所,Python 越来越受欢迎——正是因为这个原因。
  • Fortran 是高性能科学计算的de facto 语言。它具有过去几十年的大多数语言所缺乏的东西:focus。做一件事并做好。 OOP 功能包含在语言中,足以满足它旨在解决的问题领域的需求。 Python 之所以成为 HPSC 中的一个极好的工具,主要是因为它简单、灵活并且有一套很棒的工具。如果我的项目需要 GUI、访问网络/操作系统或与其他语言交互,我从不怀疑今天选择 Python。但是,你知道 Python 库是如何进行繁重计算的吗? Fortran.
【解决方案2】:

为了总结这一切,我决定给出一个我正在尝试做的工作示例。再次感谢@Rodrigo Rodrigues 阐明子模块 的真正含义。我不确定这种方法是否是正确的做法,但它对我有用。

任务

  • 使用在基类中定义的子例程sub 定义类型
  • 定义几个子类型,sub 根据需要被覆盖

基本模块

module BaseClass

    implicit none

    type, abstract :: Base    ! <-- the base class with subroutine "sub"
    contains
        procedure(sub_interface), nopass, deferred :: sub
    end type

    interface
        subroutine sub_interface(i)    ! <-- the interface is defined here
            implicit none
            integer, intent(in) :: i
        end subroutine sub_interface
    end interface

end module BaseClass

子模块

module ChildClass

    implicit none

    type, extends(Base) :: Child    ! <-- we extend the Base Class
    contains
        procedure, nopass :: sub
    end type

    interface
        module subroutine sub(i)    ! <-- the interface for the submodule (unfortunately we have to declare the entire thing again)
            implicit none
            integer, intent(in) :: i
        end subroutine sub
    end interface

end module ChildClass

子模块

submodule (ChildClass) ChildSub

contains

    module procedure sub    ! <-- we finally get to define the subroutine
        print*, "The answer is :", i
    end procedure

end submodule

计划

program test

    use ChildClass

    implicit none

    type(Child) :: c
    integer     :: i

    do i=1, 10
        call c%sub(i)
    end do

end program test

我们现在可以有多个子类,它们都扩展了基类并相应地调用sub。我个人不太喜欢的是我们必须声明sub 两次,一次是在基类的接口中,一次是在子类的接口中,才能使用子模块。这是代码重复,但也许可以做得更好。

【讨论】:

  • 能否分享一下如何构建这三个模块文件和主程序的makefile?
  • 我不再使用 Fortran 进行开发,但我检查了我还有什么!
  • 提前致谢 :)
猜你喜欢
  • 1970-01-01
  • 2015-11-18
  • 2021-12-07
  • 2022-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-07
  • 2014-10-10
相关资源
最近更新 更多