1.5. 函数与子程序
Fortran 中有两种过程的组织形式:函数 (function) 和 子程序 (subroutine)。
1.5.1. 函数(Function)
1.5.1.1. 基本语法
! 函数定义
function add(a, b) result(sum)
implicit none
integer, intent(in) :: a, b
integer :: sum ! 返回值
sum = a + b
end function add
! 调用
integer :: x = 3, y = 4, z
z = add(x, y) ! z = 7
1.5.1.2. 简写形式
! 省略 result 子句(函数名作为返回值变量)
integer function square(x)
implicit none
integer, intent(in) :: x
square = x * x
end function square
小技巧
推荐总是使用 result 子句,这样函数名和返回值变量名分离更清晰。
1.5.2. intent 属性
属性 |
含义 |
效果 |
|---|---|---|
|
输入参数 |
过程内不可修改 |
|
输出参数 |
进入过程时值未定义 |
|
输入输出参数 |
可读可修改 |
subroutine calc(a, b, c)
implicit none
real, intent(in) :: a ! 只读
real, intent(out) :: b ! 只写
real, intent(inout) :: c ! 可读可写
b = a * 2.0
c = c + a
end subroutine
重要
在可能的情况下**始终使用 intent** (标注 intent 属性):
- 帮助编译器检查错误
- 生成更优化的代码
- 提高代码自文档性
1.5.3. 子程序(Subroutine)
子程序不返回值(但可以通过参数返回)。
subroutine swap(a, b)
implicit none
integer, intent(inout) :: a, b
integer :: temp
temp = a
a = b
b = temp
end subroutine swap
! 调用
integer :: x = 3, y = 5
call swap(x, y) ! x=5, y=3
1.5.4. 函数 vs 子程序
特性 |
函数 (function) |
子程序 (subroutine) |
|---|---|---|
返回值 |
以一个返回值为主 |
无返回值,通过参数输出 |
调用方式 |
|
|
用法 |
表达式内使用 |
作为独立语句 |
适合场景 |
数学计算、判断 |
修改参数、I/O 操作 |
1.5.5. 递归过程
! 递归函数
recursive function factorial(n) result(res)
implicit none
integer, intent(in) :: n
integer :: res
if (n <= 1) then
res = 1
else
res = n * factorial(n - 1)
end if
end function factorial
! 递归子程序
recursive subroutine hanoi(n, from, to, aux)
implicit none
integer, intent(in) :: n
character(1), intent(in) :: from, to, aux
if (n == 1) then
write(*, '(A, A, A, A)') "移动盘 1 从 ", from, " 到 ", to
else
call hanoi(n - 1, from, aux, to)
write(*, '(A, I0, A, A, A, A)') "移动盘 ", n, " 从 ", from, " 到 ", to
call hanoi(n - 1, aux, to, from)
end if
end subroutine hanoi
小心
递归函数必须使用 recursive 关键字!
Fortran 95 之前的版本不支持递归。
1.5.6. pure 与 elemental 过程
1.5.6.1. pure 过程
不产生任何副作用的函数,可安全并行执行:
pure function square(x) result(res)
implicit none
real, intent(in) :: x
real :: res
res = x * x
end function
1.5.6.2. elemental 过程
对标量定义,但可自动逐元素作用于数组:
elemental function celsius_to_fahrenheit(c) result(f)
implicit none
real, intent(in) :: c
real :: f
f = c * 9.0 / 5.0 + 32.0
end function
! 直接传入数组
real :: temps(5) = [0.0, 10.0, 20.0, 30.0, 40.0]
write(*, *) celsius_to_fahrenheit(temps)
! 输出: 32.0 50.0 68.0 86.0 104.0
1.5.7. 可选参数与关键字参数
subroutine write_log(msg, level, unit)
implicit none
character(*), intent(in) :: msg
integer, intent(in), optional :: level
integer, intent(in), optional :: unit
integer :: lvl, u
lvl = 0
if (present(level)) lvl = level
u = 6 ! 标准输出
if (present(unit)) u = unit
write(u, '(A, I2)') trim(msg), lvl
end subroutine
! 调用(可选参数可省略)
call write_log("信息") ! 全部使用默认值
call write_log("警告", level=1) ! 指定关键参数
call write_log("错误", level=2, unit=0) ! 指定多个
小技巧
使用 present() 检查可选参数是否被传入。
关键字参数使调用更清晰,避免记错参数顺序。
1.5.8. interface 关键字
用于声明外部过程或操作符的重载:
interface
subroutine external_sub(x, y)
import :: dp ! 导入主调模块的 dp 类型
real(dp), intent(in) :: x
real(dp), intent(out) :: y
end subroutine
end interface
! 操作符重载
interface operator(+)
procedure add_vectors
end interface