在 Fortran 中重载等于运算符

Overloading the equals operator in Fortran

有没有一种方法可以重载 = 运算符,以便您可以编写如下示例中的赋值:

  module constants_mod
    integer,parameter :: dpn = selected_real_kind(14)
  end module

  module vectorField_mod
    use constants_mod
    implicit none
    private

    public :: vectorField
    public :: allocateX,allocateY,allocateZ
    public :: delete
    ! public :: operator(=)

    type vectorField
      integer,dimension(3) :: sx,sy,sz
      real(dpn),dimension(:,:,:),allocatable :: x,y,z
    end type

  interface delete
    module procedure deallocateVectorField
  end interface

  ! interface operator (=)
  !   module procedure vectorAssign
  ! end interface

  contains

    ! function vectorAssign(f) result(q)
    !   implicit none
    !   real(dpn),intent(in) :: f
    !   type(vectorField) :: q
    !   q%x = f; q%y = f; q%z = f
    ! end function

    ! subroutine vectorAssign(f,g)
    !   implicit none
    !   type(vectorField),intent(inout) :: f
    !   real(dpn),intent(in) :: g
    !   f%x = g; f%y = g; f%z = g
    ! end subroutine

    subroutine allocateX(field,Nx,Ny,Nz)
      implicit none
      type(vectorField),intent(inout) :: field
      integer,intent(in) :: Nx,Ny,Nz
      if (allocated(field%x)) deallocate(field%x)
      allocate(field%x(Nx,Ny,Nz))
      field%sx = shape(field%x)
    end subroutine

    subroutine allocateY(field,Nx,Ny,Nz)
      implicit none
      type(vectorField),intent(inout) :: field
      integer,intent(in) :: Nx,Ny,Nz
      if (allocated(field%y)) deallocate(field%y)
      allocate(field%y(Nx,Ny,Nz))
      field%sy = shape(field%y)
    end subroutine

    subroutine allocateZ(field,Nx,Ny,Nz)
      implicit none
      type(vectorField),intent(inout) :: field
      integer,intent(in) :: Nx,Ny,Nz
      if (allocated(field%z)) deallocate(field%z)
      allocate(field%z(Nx,Ny,Nz))
      field%sz = shape(field%z)
    end subroutine

    subroutine deallocateVectorField(field)
      implicit none
      type(vectorField),intent(inout) :: field
      deallocate(field%x,field%y,field%z)
      field%sx = 0; field%sy = 0; field%sz = 0
    end subroutine

  end module

  program test
  use constants_mod
  use vectorField_mod
  implicit none
  type(vectorField) :: a
  integer :: N = 1
  real(dpn) :: dt = 0.1
  call allocateX(a,N,N,N)
  call allocateY(a,N,N,N)
  call allocateZ(a,N,N,N)

  a%x = dble(1.0) ! want to avoid this
  a%y = dble(1.0) ! want to avoid this
  a%z = dble(1.0) ! want to avoid this

  a = real(1.0,dpn) ! want this instead (does not compile)

  call delete(a)

  end program

我尝试了两种不同的方法(在评论中显示),但我收到错误消息,指出通用规范中存在语法错误(用于宣传 = 运算符)。

对于定义的赋值 operator(=) 不正确,但 assignment(=) 是:参见 F​​ortran 2008 12.4.3.4.3。所以你反而想要两个肿块

public :: assignment (=)

interface assignment (=)
  module procedure vectorAssign
end interface

请注意,定义分配的正确方法是通过您拥有的子程序(尽管受让人可以使用 intent(out) 而不是 intent(inout))。

是的,您可以重载赋值运算符。赋值运算符的语法和要求与其他运算符不同,因为语义根本不同:所有其他运算符都基于一个或两个参数计算一个新值,而不更改参数,而赋值会更改左侧的值参数。

在你的情况下,我认为它应该是这样的:

module vectorField_mod

! ...

  interface assignment (=)
    module procedure vectorAssign
  end interface

contains

  ! ...

  subroutine vectorAssign(f,g)
    implicit none
    type(vectorField),intent(out) :: f
    real(kind = dpn), intent(in) :: g
    f%x = g
    f%y = g
    f%z = g
  end subroutine vectorAssign

end module vectorField_mod

= 不是运算符,它是 Fortran 中的赋值,它们是非常不同的野兽。

对于在 Fortran 90 中发现并在其他答案中得到很好解释的经典可能性,Fortran 2003 增加了一种更好的可能性,可以将重载运算符和赋值与派生类型绑定。

这样你就可以确定你不会在没有赋值的情况下导入类型(在这种情况下要注意 public 和 private 语句!)。它可能会产生非常不愉快的后果并且很难调试:

type vectorField
  integer,dimension(3) :: sx,sy,sz
  real(dpn),dimension(:,:,:),allocatable :: x,y,z
contains
  procedure :: assignVector
  generic :: assignment(=) => assignVector
end type

这样你就不必那么小心不要忘记 public :: assignment (=)