【问题标题】:Daisy-chaining USE statements with Fortran modules使用 Fortran 模块的菊花链 USE 语句
【发布时间】:2018-10-05 14:08:30
【问题描述】:

我的问题的上下文并不是很容易描述,所以只要说我有充分的理由尝试构建一个 DLL F90 项目,这样就足够了 -

  • 我有一些低级模块(特点是很少或没有 依赖于其他模块),
  • 一些中级模块(即 主要使用来自低级的数据执行中间计算 模块)和
  • 一些高级模块(和主 DLL) 将这些计算的结果组合成输出。

我的目标结构的简化版本最终会是这样的:

  • module1(无依赖关系)
  • module2(无依赖关系)
  • 模块 3(使用模块 1)
  • module4(使用module2)
  • module5(使用 module1 参数和 module3 方法)
  • module6(使用 module2 参数和 module4 方法)
  • 主 DLL 代码(使用上述所有模块)

问题:

我是否需要在主 DLL 代码中显式使用所有模块,或者是否只需使用模块 5 和模块 6 就可以继承“最低”级别的变量和方法?

或者,module5 需要两个 USE 语句(module1 AND module3)还是只需要 module3?

而且,我还想访问一些全局常量,例如我的主 DLL 代码(例如 pi)中的 module1,因此我需要 module1 公共变量位于全局命名空间中。

【问题讨论】:

  • 我很想说这是this other question 的副本。这些概念是完全不同的,但是理解那里所说的内容将使这个问题的答案变得清晰。请阅读该内容和答案,如果没有帮助,请告诉我们。

标签: fortran


【解决方案1】:

我是否需要在主 DLL 代码中显式使用所有模块, 或者“最低”级别的变量和方法是否会被继承 只使用module5和module6?

您不需要需要将模块一直使用到依赖项,只是为了访问实体如果该实体在使用的模块中公开 >.

或者,module5 需要两个 USE 语句(module1 AND module3)还是只需要 module3?

只需使用module5,您就可以访问:

  • module5 本身内声明的任何模块实体,标记为publicprotected
  • module5 中由 USE 关联访问的任何实体,标记为 public by module5(实际上,如果未指定,则 public 是默认可访问性)。如果一个实体通过 USE 关联从module1module3 访问,但被module5 标记为private,它将无法访问。

我试图在以下示例中涵盖尽可能多的情况。我只使用了变量声明,但同样适用于变量、过程、用户定义类型、运算符、接口......

module module0
  ! Utiliy module with global constants, could be used at any level.

  character(2) :: w = 'w0'
end

module module1
  ! Low level module. Exposes all the symbols that are not marked as private,
  ! both defined locally or accessed by use from 'module0'.

  use :: module0
  private :: z
  character(2) :: x1 = 'x1', y1 = 'y1', z = 'z1'

  ! defined entities: w, x1, y1, z 
  ! public entities : w, x1, y1
end

module module2
  ! Also low level module, but default access modifier was changed to private,
  ! so it exposes only symbols marked as public ('z' isn't).

  use :: module0
  public :: w, x2, y2
  private
  character(2) :: x2 = 'x2', y2 = 'y2', z = 'z2'

  ! defined entities: w, x2, y2, z 
  ! public entities : w, x2, y2
end

module module3
  ! Uses all public names from 'module1' (including 'w' that is from 'module0'),
  ! but only exposes some of them. Also, defines and exposes local symbols.

  use :: module1
  private :: x3, y1
  character(2) :: x3 = 'x3', y3 = 'y3'

  ! defined entities: w, x1, y1, x3, y3
  ! public entities : w, x1, y3
end

module module4
  ! Here, only selected symbols are accessed from 'module2', and 'w' has been
  ! renamed into 'w2' to avoid name-conflict with locally defined name 'w'
  ! (a compile error would had been thrown).

  use :: module2, only: w2 => w, x2
  public :: w, x2, y4
  private
  character(2) :: w = 'w4', x4 = 'x4', y4 = 'y4'

  ! defined entities: w, w2, x2, x4, y4
  ! public entities : w, x2, y4
end

module module5
  ! This module can use symbols from lowest level modules that are made public
  ! by 'module3', without explicitly using those modules.

  use :: module3
  character(2) :: z = 'z5'

  ! defined entities: w, x1, y3, z
  ! public entities : w, x1, y3, z
end

module module6
  ! As 'y2' is not exposed by 'module4', we could have access to it by using
  ! 'module2' directly. There is no name-conflict between 'w' from 'module0' 
  ! and from 'module2' because both relate to the same entity. There would be
  ! conflict with 'w' from 'module4' though, hence the rename.

  use :: module0
  use :: module2
  use :: module4, w4 => w
  public :: w, x2, y4, z
  private
  character(2) :: z = 'z6'

  ! defined entities: w, w4, x2, y2, y4, z
  ! public entities : w, x2, y4, z
end

我强烈建议您尽可能尝试使用显式导入,因为它可以使您的代码更清晰并避免名称冲突。作为一般规则,请尝试对模块中的公共实体使用独特的名称,或在 USE 语句中使用重命名子句。

这是前面模块的使用示例:

program main
  ! There aren't namespaces in Fortran (yet), so attention shall be paid when
  ! naming symbols meant to be accessed by use association, to avoid conflicts.
  ! That's why explicit imports are encouraged, as well as implicit none.

  use :: module5
  use :: module6, z6 => z
  implicit none      
  character(2) :: v = 'v#'

  call test_a
  call test_b
  call test_c

contains
  subroutine test_a
    ! You can access used and defined names in procedures by host association.

    print '(5a3)', v, w, x1, y3, z   ! output: v# w0 x1 y3 z5
    print '(5a3)', v, w, x2, y4, z6  ! output: v# w0 x2 y4 z6
  end

  subroutine test_b
    ! Also, you can use modules locally inside procedures. In this case, local
    ! names "shadow" host associated names, as with 'z' from 'module6' here.

    use :: module6
    print '(5a3)', v, w, x2, y4, z  ! output: v# w0 x2 y4 z6
  end

  subroutine test_c
    ! There is no name-conflict error between host and local symbols; the local
    ! definition (or use association) always "shadows" the host associated name.

    use :: module4, only: w
    character(2) :: v = 'v_', z = 'z_'
    print '(5a3)', v, w, x1, y3, z   ! output: v_ w4 x1 y3 z_
  end
end

为了完整起见,我要提到Fortran 2018 standard 包含一个名为从模块访问的实体的默认可访问性 的新功能,它允许您将模块名称放入@987654336 @ 或 private 语句,将所述可访问性修饰符应用于该模块中所有使用的实体。

如果模块 a 使用模块 b,则它的实体的默认可访问性 来自 b 的访问是公开的。为每个指定另一个可访问性 实体笨拙且容易出错。现在可以为名称 包含在公开实体名称列表中的模块 或私人的公开或私人声明。这将默认设置为 从该模块访问的所有实体。

我知道今天(2018 年)唯一包含此功能的编译器是 Intel Visual Fortran 19.0

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-28
    • 1970-01-01
    • 2020-06-06
    • 1970-01-01
    • 1970-01-01
    • 2014-11-25
    • 2017-09-17
    相关资源
    最近更新 更多