有没有办法有条件地设置 public 数据结构的类型?

Is there a way to conditionally set the type of a public data structure?

有没有办法有条件地设置 public 数据结构?

例如:

MODULE EXAMPLE

  USE DATA_TYPE_Define, ONLY: DATA_TYPE_A, DATA_TYPE_B
  USE PARAMETER,        ONLY: CaseAisTrue

  ! Disable all implicit typing
  IMPLICIT NONE

  ! ------------
  ! Visibilities
  ! ------------
  ! Everything private by default
  PRIVATE
  ! The shared data
  PUBLIC :: DATA

  ! ------------------------------------------------
  ! The shared data 
  ! ------------------------------------------------

  IF (CaseAisTrue) Then
     TYPE(DATA_TYPE_A), SAVE :: DATA
  ELSE
     TYPE(DATA_TYPE_B), SAVE :: DATA
  END IF


CONTAINS
  ...

其中DATA_TYPE_A和DATA_TYPE_B是两种不同的数据structures/derived类型。

除了引入更多public变量之外,还有什么好的设置方法吗?

谢谢!

我看到两个选项。

  1. 这可以在运行时改变吗?然后,您可能需要稍后在代码中的其他任何地方访问相同的 DATA 的唯一原因是因为 DATA_TYPE_ADATA_TYPE_B 具有基本相同的 API。这是一个典型的 object-oriented 编程模式示例:您希望两种数据类型共享相同的 API:
! The base class
type, abstract, public :: DATA_TYPE
end type DATA_TYPE

type, public, extends(DATA_TYPE) :: DATA_TYPE_A
   [...]
end type DATA_TYPE_A

type, public, extends(DATA_TYPE) :: DATA_TYPE_B
   [...]
end type DATA_TYPE_B

如果您需要在访问的数据类型之间不断切换,您可以为它们设置两个单独的变量:

! Actual shared data, here or elsewhere
type(DATA_TYPE_A), target, SAVE :: DATA_A
type(DATA_TYPE_B), target, SAVE :: DATA_B

并使用指针指向它们:

class(DATA_TYPE), public, pointer :: DATA => null()

! Set pointer
subroutine set_data(mode)
   integer, intent(in) :: mode
   select case (mode)
     case (1);     DATA => DATA_A
     case (2);     DATA => DATA_B
     case default; nullify(DATA)
   end select  
end subroutine set_data

否则,如果你不经常更改它,你可以使用多态分配,这样会更优雅:

! Actual shared data
class(DATA_TYPE), allocatable :: DATA

并在需要时分配正确的类型:

! Polymorphic allocation
subroutine set_data(mode)
   integer, intent(in) :: mode
   integer :: ierr
   
   ! Deallocate first
   deallocate(DATA,stat=ierr) ! don't stop if not already allocated

   select case (mode)
     case (1);     allocate(DATA,source=DATA_A) 
     case (2);     allocate(DATA,source=DATA_B)
     case default; return
   end select  
end subroutine set_data
  1. 是否应该在编译时修复(parameter化)?然后,编译器 pre-processor 将是最有用的。例如,对于 C pre-processor,您将有:

#define DATATYPE_IS_A


#ifdef DATATYPE_IS_A
   type(DATA_TYPE_A), parameter :: DATA = [...]
#else
   type(DATA_TYPE_B), parameter :: DATA = [...]
#endif

后一个选项在 编译之前执行,即数据类型是强制执行的,永远不能更改。