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

Module 私有,保存Fortran 90模块中变量的属性,module,fortran,fortran90,Module,Fortran,Fortran90,我试图使用模块中的private属性为某些变量添加访问限制,但我需要在该模块内例程的后续调用中使用这些变量: module MyMod private integer,allocatable :: A(:) public :: init,calc contains subroutine init() ! allocating and initializing A end subroutine init subroutine calc()

我试图使用模块中的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的答案是肯定的,那么我认为我可以对这个变量使用save属性。如果我错了,请纠正我

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


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

对于第一个问题,Fortran 2008标准第4.5.2.2条§3规定:

如果类型定义是私有的,那么类型名以及类型的结构构造函数4.5.10只能在包含该定义的模块及其子体中访问

因此,将无法从模块或子模块子代之外的任何位置访问

对于第二个问题,可以使用save here。这与可访问性属性无关。事实上,从Fortran 2008开始,这就意味着模块变量,参见Fortran 2008标准第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内部,您创建了一个_的副本,该副本只能在模块内访问。只要calc是模块或其子模块的一部分,它就具有对a的完全访问权限。

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

对于第一个问题,Fortran 2008标准第4.5.2.2条§3规定:

如果类型定义是私有的,那么类型名以及类型的结构构造函数4.5.10只能在包含该定义的模块及其子体中访问

因此,将无法从模块或子模块子代之外的任何位置访问

对于第二个问题,可以使用save here。这与可访问性属性无关。事实上,从Fortran 2008开始,这就意味着模块变量,参见Fortran 2008标准第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内部,您创建了一个_的副本,该副本只能在模块内访问。只要calc是模块或其子模块的一部分,它就可以完全访问.

以添加save属性的含义

此属性正好提供了您从F2008 5.3.16开始想要的效果:

SAVE属性指定程序单元或子程序的局部变量在执行RETURN或END语句后保留其关联状态、分配状态、定义状态和值,除非[此处不适用]

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

这意味着,在调用init之后,它可能会分配一个值并设置子例程返回后保留的状态。这些值在调用calc时可用。当然,init和calc都通过主机关联引用相同的值

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

添加save属性的含义

此属性正好提供了您从F2008 5.3.16开始想要的效果:

SAVE属性指定程序单元或子程序的局部变量在执行RETURN或END语句后保留其关联状态、分配状态、定义状态和值,除非[此处不适用]

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

Th 是指,在调用init之后,它可能会分配一个值,并设置子例程返回后保留的状态值。这些值在调用calc时可用。当然,init和calc都通过主机关联引用相同的值


您提到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

这是另一种在避免“保存”的同时完成您想要做的事情的方法

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

我不确定你的第三个问题。你能详细说明一下吗?你想达到什么目的?谢谢你的回复。我知道该变量是模块专用的。我的主要问题是:我使用init初始化它,init是从使用模块的程序main.F90调用的。然后,从main.F90调用例程calc。现在,一般来说,如果变量A的作用域由于具有private属性而丢失,那么在calc中使用A是不安全的。你能详细说明一下吗?你想达到什么目的?谢谢你的回复。我知道该变量是模块专用的。我的主要问题是:我使用init初始化它,init是从使用模块的程序main.F90调用的。然后,从main.F90调用例程calc。现在,一般来说,如果变量A的范围由于具有private属性而丢失,那么在calc中使用A将不安全。谢谢您的建议。我当然会尝试使用这个想法,它似乎源于F2003的面向对象特性。你能想到这个方法和使用save属性performance-wise之间有什么区别吗?是的,F2003在派生类型中引入了过程封装。我从未测试过“save”变量的性能。但是使用save属性被认为不是一个好的编程实践。是一个比我能说得更好的评论。谢谢你的建议。我当然会尝试使用这个想法,它似乎源于F2003的面向对象特性。你能想到这个方法和使用save属性performance-wise之间有什么区别吗?是的,F2003在派生类型中引入了过程封装。我从未测试过“save”变量的性能。但是使用save属性被认为不是一个好的编程实践。这是一个比我说得更好的评论。