我正在尝试在模块中为某些变量(使用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
属性。如果我错了,请纠正我?
这是执行此任务的正确方法吗?
答案 0 :(得分:3)
是的,如果您在没有任何进一步说明的情况下将私有语句放入模块中,则将默认辅助功能设置为private
。
对于第一个问题,Fortran 2008标准(Cl.4.5.2.2§3)指出:
如果类型定义是
private
,那么类型名称以及类型的结构构造函数(4.5.10)只能在包含定义的模块中及其后代中访问。
因此,无法从模块或子模块(后代)之外的任何位置访问A
。
对于第二个问题,是 - 你可以在这里使用save
。 (这与辅助功能属性无关)。实际上,从Fortran 2008开始,模块变量就是隐含的,参见Fortran 2008 Standard(Cl.5.3.16§4)[感谢@francescalus]:
在主程序,模块或子模块的作用域单元中声明的变量,公共块或过程指针隐式具有SAVE属性,可以通过显式规范确认[...]
如果我理解你的第三个问题,那就与初始化有关。您可以使用函数/子例程来实现这一点,您可以将数组传递给它进行初始化:
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
。
答案 1 :(得分:1)
添加answer by Alexander Vogt save
属性的含义。
此属性精确地给出了您之后的效果(来自F2008 5.3.16):
SAVE属性指定程序单元或子程序的局部变量在执行RETURN或END语句后保留其关联状态,分配状态,定义状态和值,除非[此处不适用]
在您的示例中,A
是模块的局部变量(因此是程序单元)MyMod
。
这意味着,在调用init
之后,可能会分配A
并设置在子例程返回后保留状态的值。然后,可以通过调用calc
获得这些值。当然,init
和calc
都指向相同的A
到主机关联。
你提到Fortran 90,所以有一个微妙的变化(再次提到其他答案)。在Fortran 2008模块变量之前,需要save
属性在某些情况下明确地给出此效果。如果您不确定编译器如何处理代码,那么明确提供save
属性是没有害处的(无论如何,有些人会说它是一种好的做法)。
答案 2 :(得分:1)
这是在避免“保存”的同时完成您想要做的事情的另一种方式。
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