4.2. 函数值
在凹语言中,函数可以被当作一种特殊的值,例如:
// 版权 @2023 凹语言 作者。保留所有权利。
func Inc(i: i32) => i32 { return i + 1 }
func Dec(i: i32) => i32 { return i - 1 }
func main {
f := Inc
println(f(42)) // 43
f = Dec
println(f(42)) // 41
}
上例中,f
即为函数值,函数值可以被调用,调用方法与函数调用无异。
函数的类型由其参数以及返回值类型决定,通常这些信息被称为函数签名(Signature),如果两个函数 A 和 B 拥有相同签名,意味着它们:
- 参数个数相同;
- 返回值个数相同;
- 对于任意 n,函数 A 的第 n 个参数的类型与 B 的第 n 个参数类型相同;
- 对于任意 m,函数 A 的第 m 个返回值的类型与 B 的第 m 个返回值类型相同。
函数值的类型也是通过函数签名定义的,比如上例中函数值 f
的类型为 func(i32) => i32
,因此上例中 f
的快捷声明 f := Inc
等价于:
f: func(i32) => i32 // f == nil
f = Inc
与其他类型的值一样,函数值也为0值初始化,对应值为
nil
在凹语言中,类型不同的值不能相互赋值,这一点对函数值同样有效,由于函数类型由签名确定,因此将一个函数赋值给签名不同的函数值被视为非法,例如:
func Inc(i: i32) => i32 { return i + 1 }
func main {
f: func(i32)
f = Inc // 编译错误
}
既然被称为“值”,意味着函数值可以作为参数、和返回值在不同函数间传递,例如:
// 版权 @2023 凹语言 作者。保留所有权利。
func inc(i: i32) => i32 { return i + 1 }
func dec(i: i32) => i32 { return i - 1 }
func getFunc(opCode: i32) => func(i32) => i32 {
if opCode == 0 {
return inc
} else if opCode == 1 {
return dec
} else {
return nil
}
}
func useFunc(i: i32, f: func(i32) => i32) {
if f == nil {
println("f == nil")
return
}
println(f(i))
}
func main {
useFunc(42, getFunc(0)) // 43
useFunc(42, getFunc(1)) // 41
useFunc(42, getFunc(2)) // f == nil
getFunc(2)(42) // 运行时异常
}
与其他基本类型不同,函数值只能与 nil
比较,既:函数值位于操作符 ==
、!=
左侧时,右侧只能为 nil
,对两个非常量函数值执行比较操作被视为非法。
如果被调用的函数值为 nil
,将触发不可恢复的运行时异常。
函数值与 C 系语言中的函数指针作用类似,可以更灵活的动态调整执行分支。但需要指出的时,相比于直接调用函数,调用函数值有一些额外消耗,性能敏感的场合需要格外注意。