Fortran 90 模块中变量的私有、保存属性

Private, Save attributes for variables in Fortran 90 modules

我正在尝试对模块中的某些变量(使用 private 属性)添加访问限制,但我需要在该模块中的后续例程调用中使用这些变量:

module MyMod

  private 
  integer,allocatable :: A(:)

  public :: init,calc

contains

  subroutine init()

    ! allocating and initializing A

  end subroutine init

  subroutine calc()

    ! Using A

  end subroutine

 end module

问题:

  1. 这个私有变量不会在use这个模块的程序范围内吗

  2. 如果对 1 的回答是肯定的,那么我认为我可以为这个变量使用 save 属性。如有错误请指正?

  3. 这是执行此任务的正确方法吗?

是的,如果您在没有任何进一步说明的情况下将 private 语句放入模块,则可以将默认可访问性设置为 private

对于第一个问题,Fortran 2008 标准(Cl. 4.5.2.2 §3)指出:

If a type definition is private, then the type name, and thus the structure constructor (4.5.10) for the type, are accessible only within the module containing the definition, and within its descendants.

因此 A 将无法从模块或子模块(后代)之外的任何地方访问。

对于第二个问题,是的 - 您可以在此处使用 save。 (这与可访问性属性无关)。事实上,从 Fortran 2008 开始,这对于模块变量是隐含的,参见 Fortran 2008 标准(Cl. 5.3.16 §4)[感谢@francescalus]:

A variable, common block, or procedure pointer declared in the scoping unit of a main program, module, or submodule implicitly has the SAVE attribute, which may be confirmed by explicit specification [...]

如果我没看错你的第三个问题,那是和初始化有关的。你可以用一个 function/subroutine 来实现这一点,你将一个数组传递给它来进行初始化:

module MyMod
! ...
contains
! ...
subroutine init( A_in )
  implicit none
  integer, intent(in) :: A_in(:)

  ! allocating and initializing A
  allocate( A(size(A_in)) )
  A = A_in
end subroutine

end module

init() 中创建一个 A_in 的副本,它只能在模块中访问。只要 calc() 是模块(或其子模块)的一部分,它就可以完全访问 A

添加 save 属性的含义。

此属性准确地给出了您想要的效果(来自 F2008 5.3.16):

The SAVE attribute specifies that a local variable of a program unit or subprogram retains its association status, allocation status, definition status, and value after execution of a RETURN or END statement unless [something not applicable here]

在您的示例中,A 是模块的局部变量(也是程序单元)MyMod

这意味着,在调用 init 之后,大概会分配 A 并设置子例程 returns 之后保留状态的值。这些值随后可用于调用 calcinitcalc当然都是通过主机关联指代同一个A

你提到了 Fortran 90,所以有一个微妙的变化(同样在另一个答案中提到)。在 Fortran 2008 之前,模块变量需要 save 属性在某些情况下显式给出才能产生这种效果。如果您不确定编译器如何处理代码(有些人会说这是一种很好的做法),那么显式地提供 save 属性并没有什么坏处。

这是完成您想做的事情同时避免 'save' 的另一种方法。

module MyMod

  private
  public :: myType, init

  type myType
    private
    integer, allocatable :: A(:)
  end type myType

contains

  subroutine init(obj, n)

    type(myType), intent(inout) :: obj
    integer, intent(in) :: n

    allocate(obj%A(n), source=-9999999)

  end subroutine init

end module MyMod

program test

  use MyMod, only: myType, init 

  type(myType) :: m ! m is an opaque object

  call init(m, 10)

end program test

在这个例子中,m 是一个不透明的对象——我可以创建对象,传递它,但不能访问它的内容(在这个例子中是数组 A)。这样,我就隐藏了我的数据。只要我的对象 m 在范围内,我就可以通过模块 myMod.

中包含的例程对隐藏在对象中的数据进行操作

如果您可以访问支持 Fortran 2003 的现代编译器,则可以将模块重写为

module MyMod

  private
  public :: myType

  type myType
    private
    integer, allocatable :: A(:)
  contains
    procedure, public :: init
  end type myType

contains

  subroutine init(obj, n)

    class(myType), intent(inout) :: obj
    integer, intent(in) :: n

    allocate(obj%A(n), source=-9999999)

  end subroutine init

end module MyMod

program test

  use MyMod, only: myType

  type(myType) :: m ! m is an opaque object                                                         

  call m%init(10)

end program test