在 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(=)
是:参见 Fortran 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 (=)
有没有一种方法可以重载 =
运算符,以便您可以编写如下示例中的赋值:
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(=)
是:参见 Fortran 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 (=)