4

我已经用 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) 处的参数 'this' 中的类型不匹配;将 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_type1and compute_type2。当访问这些子程序时,这在代码中看起来非常丑陋和冗余。例如call myType1%compute_type1. 第二个选项(例如Overloaded fortran interface with different ranks类型绑定函数重载 in Fortran 2003)似乎更好,是区分绑定名称和过程名称。例如,类型定义将包括procedure :: compute type => compute_type1. 这解决了访问子例程时的问题,但是在开发具有许多实现相同绑定名称的派生类型的大型项目时,我可以看到问题。我宁愿不必跟踪我在任何给定项目中拥有和未使用的子例程名称。这会使名称最终变得很长且可读性降低。

所以我的问题有3个组成部分:

  • this%<var_name>在类型绑定过程中,对于类成员的显式类型是否有更简洁的替代方法?
  • 有没有办法让编译器认识到应该根据class(<class_name>) :: this语句绑定过程?当前重载子例程/函数名称的方法似乎是 90/95 标准的产物,该标准不允许将它们绑定到类型。
  • 如果没有,是否有与此实现相关的一些性能提升?这两个问题似乎都可以在编译时解决,我很乐意为提高表达能力做出牺牲。
4

1 回答 1

5

这更像是一个扩展注释,但由于编译器失败,您似乎被迫推测。我已经用 gfortran 4.8.3 编译了代码,没有错误,并且得到了预期的结果。另外,在我看来,你想要发生的事情应该发生。

另一个后果是,两个独立的派生类型似乎不能绑定同名的子例程(如错误消息所示)。

虽然调用了两个子例程,compute但它们位于单独的模块中,这是允许的,尽管您的use语句使call compute(...)(您没有这样做)模棱两可。如果类型定义在同一个模块中,那么您将不得不求助于这个procedure :: compute => compute_typex技巧,但call mytype1%compute仍然可以接受。

我建议如果您compute通过类型绑定公开子例程,那么您将它们private放在模块中,或者至少不要显式地使用use它们。[也就是说,有use mod1, only : type1。]

至于你是否被子type%...程序困住,那么是的,我认为你是。也就是说,在 Fortran 2008 下有associate构造

subroutine compute(this)
  class(type1), intent(inout) :: this
  associate (x => this%x, y => this%y)
    ...
  end associate
end subroutine

但在这种情况下并没有太大的收获。还有其他可怕的技巧我不会详细说明。

于 2014-01-24T23:35:43.050 回答