OOP Fortran,模块中定义的派生类型和对象:有什么缺点吗?
OOP Fortran, derived types and objects defined within modules: are there any cons?
这是 GNU Fortran (gfortran) 编译得很好的一个简单的 Fortran95 代码:
Module Module1
Implicit None
Type MyType
Real(Kind=8) :: x, y
Integer :: n
End Type
Contains
Real(Kind=8) Function Calc(self)
Type(MyType) :: self
Calc = self%x**self%n + self%y**self%n
End Function
End Module
Program Main
Use Module1
Implicit None
Type(MyType) :: A
A = MyType(3.0, 4.0, 2)
Write(*,*) Calc(A)
End Program Main
在这种情况下,派生类型 MyType
的对象 A
在 Main
中创建并初始化。调用 Calc()
并打印其结果。现在有一个稍微不同的代码:
Module Module1
Implicit None
Type MyType
Real(Kind=8) :: x, y
Integer :: n
End Type
Type(MyType) :: A
Contains
Real(Kind=8) Function Calc(self)
Type(MyType) :: self
Calc = self%x**self%n + self%y**self%n
End Function
End Module
Program Main
Use Module1
Implicit None
A = MyType(3.0, 4.0, 2)
Write(*,*) Calc(A)
End Program Main
行数相同,结果相同。但是这里 A
被分配给 Module1
内的派生类型 MyType
,并且任何时候这个模块是 imported/used (Use
)模块,因此 A
可以在后一个模块中使用(当然前提是 A
之前已经初始化)。与全局变量类似,但不完全相同;不使用 Module1 的模块无法访问 A
.
问题是:这种编程“风格”是否存在概念上的问题?当然,无论在其他模块中用 A
做什么,都必须小心,但这也适用于其他变量。
我可以看到使用这些“旅行”对象的一些优点,但我可能会遗漏一些东西。
在您的第一个示例中,A
是一个局部变量,但在您的第二个示例中,A
是一个全局变量。全局变量通常不是一个好主意的原因有很多,在 Stack Overflow 周围的各个地方都有深入的解释 1 2 3 and Stack Exchange 4。
举个具体的例子,考虑代码:
module module2
use module1
implicit none
contains
subroutine foo()
A = MyType(1.0, 2.0, 3)
write(*,*) calc(A)
end subroutine
end module
module module3
use module2
implicit none
contains
subroutine bar()
A = MyType(2.0, 3.0, 3)
call foo()
write(*,*) calc(A)
end subroutine
end module
program main
use module3
implicit none
call bar()
end program main
而不是打印
9.0
35.0
正如预期的那样,这会打印
9.0
9.0
由于对 A
的任何更改都必然是 side effect,因此此类问题可能很难避免。另请注意,module3
并未显式 use module1
,而是通过 use module2
.
隐式使用 module1
这是 GNU Fortran (gfortran) 编译得很好的一个简单的 Fortran95 代码:
Module Module1
Implicit None
Type MyType
Real(Kind=8) :: x, y
Integer :: n
End Type
Contains
Real(Kind=8) Function Calc(self)
Type(MyType) :: self
Calc = self%x**self%n + self%y**self%n
End Function
End Module
Program Main
Use Module1
Implicit None
Type(MyType) :: A
A = MyType(3.0, 4.0, 2)
Write(*,*) Calc(A)
End Program Main
在这种情况下,派生类型 MyType
的对象 A
在 Main
中创建并初始化。调用 Calc()
并打印其结果。现在有一个稍微不同的代码:
Module Module1
Implicit None
Type MyType
Real(Kind=8) :: x, y
Integer :: n
End Type
Type(MyType) :: A
Contains
Real(Kind=8) Function Calc(self)
Type(MyType) :: self
Calc = self%x**self%n + self%y**self%n
End Function
End Module
Program Main
Use Module1
Implicit None
A = MyType(3.0, 4.0, 2)
Write(*,*) Calc(A)
End Program Main
行数相同,结果相同。但是这里 A
被分配给 Module1
内的派生类型 MyType
,并且任何时候这个模块是 imported/used (Use
)模块,因此 A
可以在后一个模块中使用(当然前提是 A
之前已经初始化)。与全局变量类似,但不完全相同;不使用 Module1 的模块无法访问 A
.
问题是:这种编程“风格”是否存在概念上的问题?当然,无论在其他模块中用 A
做什么,都必须小心,但这也适用于其他变量。
我可以看到使用这些“旅行”对象的一些优点,但我可能会遗漏一些东西。
在您的第一个示例中,A
是一个局部变量,但在您的第二个示例中,A
是一个全局变量。全局变量通常不是一个好主意的原因有很多,在 Stack Overflow 周围的各个地方都有深入的解释 1 2 3 and Stack Exchange 4。
举个具体的例子,考虑代码:
module module2
use module1
implicit none
contains
subroutine foo()
A = MyType(1.0, 2.0, 3)
write(*,*) calc(A)
end subroutine
end module
module module3
use module2
implicit none
contains
subroutine bar()
A = MyType(2.0, 3.0, 3)
call foo()
write(*,*) calc(A)
end subroutine
end module
program main
use module3
implicit none
call bar()
end program main
而不是打印
9.0
35.0
正如预期的那样,这会打印
9.0
9.0
由于对 A
的任何更改都必然是 side effect,因此此类问题可能很难避免。另请注意,module3
并未显式 use module1
,而是通过 use module2
.
module1