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
问题:
这个私有变量不会在use
这个模块的程序范围内吗
如果对 1 的回答是肯定的,那么我认为我可以为这个变量使用 save
属性。如有错误请指正?
这是执行此任务的正确方法吗?
是的,如果您在没有任何进一步说明的情况下将 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 之后保留状态的值。这些值随后可用于调用 calc
。 init
和calc
当然都是通过主机关联指代同一个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
我正在尝试对模块中的某些变量(使用 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
问题:
这个私有变量不会在
use
这个模块的程序范围内吗如果对 1 的回答是肯定的,那么我认为我可以为这个变量使用
save
属性。如有错误请指正?这是执行此任务的正确方法吗?
是的,如果您在没有任何进一步说明的情况下将 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 之后保留状态的值。这些值随后可用于调用 calc
。 init
和calc
当然都是通过主机关联指代同一个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