代码结构组织#
大多数编程语言允许您将常用的代码收集到过程中,这些过程可以通过从代码的其他部分调用它们来重复使用。
Fortran 有两种形式的过程
子程序:由
call
语句调用函数:在表达式或赋值中调用,并返回一个值
子程序和函数都可以通过参数关联访问父作用域中的变量;除非指定了 value
属性,否则这类似于按引用调用。
子程序#
子程序输入参数,称为虚拟参数,在子程序名称后面用括号指定;虚拟参数类型和属性在子程序体中声明,就像局部变量一样。
示例
! Print matrix A to screen
subroutine print_matrix(n,m,A)
implicit none
integer, intent(in) :: n
integer, intent(in) :: m
real, intent(in) :: A(n, m)
integer :: i
do i = 1, n
print *, A(i, 1:m)
end do
end subroutine print_matrix
请注意声明虚拟参数时添加的 intent
属性;此可选属性向编译器指示参数在过程中是“只读”(intent(in)
)“只写”(intent(out)
)还是“读写”(intent(inout)
)。在此示例中,子程序不会修改其参数,因此所有参数都是 intent(in)
。
始终为虚拟参数指定
intent
属性是一种良好的实践;这允许编译器检查意外错误并提供自文档。
我们可以使用 call
语句从程序中调用此子程序
program call_sub
implicit none
real :: mat(10, 20)
mat(:,:) = 0.0
call print_matrix(10, 20, mat)
end program call_sub
此示例使用所谓的显式形状数组参数,因为我们已传递了其他变量来描述数组
A
的维度;如果我们将子程序放在稍后描述的模块中,则不需要这样做。
函数#
! L2 Norm of a vector
function vector_norm(n,vec) result(norm)
implicit none
integer, intent(in) :: n
real, intent(in) :: vec(n)
real :: norm
norm = sqrt(sum(vec**2))
end function vector_norm
在生产代码中,应该使用内联函数
norm2
。
要执行此函数
program run_fcn
implicit none
real :: v(9)
real :: vector_norm
v(:) = 9
print *, 'Vector norm = ', vector_norm(9,v)
end program run_fcn
对于函数不修改其参数的做法是一种良好的编程习惯,即所有函数参数都应为
intent(in)
。此类函数称为pure
函数。如果您的过程需要修改其参数,请使用子程序。
模块#
Fortran 模块包含定义,这些定义通过 use
语句可供程序、过程和其他模块访问。它们可以包含数据对象、类型定义、过程和接口。
模块允许受控作用域扩展,从而使实体访问变得明确
模块自动生成现代过程所需的显式接口
建议始终将函数和子程序放在模块中。
示例
module my_mod
implicit none
private ! All entities are now module-private by default
public public_var, print_matrix ! Explicitly export public entities
real, parameter :: public_var = 2
integer :: private_var
contains
! Print matrix A to screen
subroutine print_matrix(A)
real, intent(in) :: A(:,:) ! An assumed-shape dummy argument
integer :: i
do i = 1, size(A,1)
print *, A(i,:)
end do
end subroutine print_matrix
end module my_mod
将此
print_matrix
子程序与在模块外部编写的子程序进行比较。我们不再需要显式传递矩阵维度,而是可以利用假定形状参数,因为模块会为我们生成所需的显式接口。这将导致子程序接口变得更加简单。
要在程序中use
模块
program use_mod
use my_mod
implicit none
real :: mat(10, 10)
mat(:,:) = public_var
call print_matrix(mat)
end program use_mod
示例:显式导入列表
use my_mod, only: public_var
示例:别名导入
use my_mod, only: printMat=>print_matrix
每个模块都应在单独的
.f90
源文件中编写。在任何use
它们的程序单元之前,都需要编译模块。