我已经用Java编程了几年;但是,我现在正在学习一门使用Fortran作为示例代码(77标准)的课程。虽然我一直认为Fortran是一种古老的语言,但我决定使用gfortran编译器尝试使用2003标准的最新实现,以了解它的优点。到目前为止,我对现代功能感到惊讶,但我遇到了一个问题,下面的例子证明了这个问题。
module mod1
type type1
real :: x
real :: y
contains
procedure :: compute
end type type1
contains
subroutine compute(this)
class(type1) :: this
this%y = this%x*2 - 1
write (*,*) this%x,this%y
end subroutine
end module mod1
module mod2
type type2
real :: x
real :: y
contains
procedure :: compute
end type type2
contains
subroutine compute(this)
class(type2) :: this
this%y = this%x - 5
write (*,*) this%x,this%y
end subroutine
end module mod2
program test
use mod1
use mod2
implicit none
type(type1) myType1
type(type2) myType2
myType1%x = 4
myType2%x = 5
call myType1%compute
call myType2%compute
end program test
这会产生编译错误:"参数类型不匹配'这个'在(1);将TYPE(type2)传递给CLASS(type1)"参考call myType2%compute
声明。
我的问题是范围问题。看来,通过class(<class_name>) :: this
语句,编译器应该能够将子例程绑定到特定的派生类型或其后代。从这里开始,编译器在概念上难以在子例程中从本地开始搜索变量定义,然后继续执行this
的特定实例的祖先树。这将消除所有明确的this%
语句,这些语句往往会使我的类型绑定过程在几个语句后难以阅读。例如,
this%tempNew(xI) = this%lamda*this%temp(xI-1)+(1-2*this%lamda)*this%temp(xI)+this%lamda*this%temp(xI+1)
似乎比
更不易读/写 tempNew(xI) = lamda*temp(xI-1)+(1-2*lamda)*temp(xI)+lamda*temp(xI+1)
在后一种情况下,通过class(<class_name>) :: this
语句很明显,每个变量都应绑定在其中。
另一个结果是,两个单独的派生类型似乎不能具有相同名称的绑定子例程(如错误消息所示)。我已经看到了两种常见的方法。首先是显式调用每个子例程,如compute_type1
和compute_type2
。访问这些子例程时,这在代码中看起来非常难看和冗余。例如call myType1%compute_type1
。第二个选项(参见例如Overloaded fortran interface with different ranks,Type-bound function overloading in Fortran 2003)似乎更好,是区分绑定名称和过程名称。例如,类型定义将包括procedure :: compute type => compute_type1
。这解决了访问子例程时的问题,但是在开发具有许多实现相同绑定名称的派生类型的大型项目时,我会发现问题。我不必跟踪我所拥有的子程序名称,也不必在任何给定的项目中使用。这往往会使名称保持相当长的时间并且最终不易阅读。
所以我的问题有3个组成部分:
this%<var_name>
,是否有更清晰的替代方法?class(<class_name>) :: this
语句绑定一个过程?当前重载子程序/函数名称的方法似乎是90/95标准的工件,它不允许将这些绑定到类型。答案 0 :(得分:5)
这更像是一个扩展注释,但由于编译器失败,您似乎被迫推测。我已经使用gfortran 4.8.3编译了代码而没有错误,并且具有预期的结果。此外,在我看来,你想要发生的事情应该发生。
另一个结果是,似乎两个单独的派生类型不能具有相同名称的绑定子例程(如错误消息所示)。
虽然两个子例程都被称为compute
,但它们位于不同的模块中,这是允许的,尽管您的use
语句会使call compute(...)
(您没有这样做)模糊不清。如果类型定义在同一模块中,那么您将不得不诉诸procedure :: compute => compute_typex
技巧,但call mytype1%compute
仍然可以接受。
我建议如果您通过类型绑定公开compute
子例程,那么在模块中将它们作为private
,或者至少,不要显式{{ 1}}他们。 [也就是说,有use
。]
至于你是否在子程序中遇到use mod1, only : type1
,那么是的,我认为你是。也就是说,根据Fortran 2008,有type%...
构造
associate
但在这种情况下,这并没有太大收获。还有其他可怕的伎俩,我不会详细说明。