在 Swift 中,@dynamicCallable 和 callAsFunction 提供了两种将类型实例作为函数调用的方式。
1. callAsFunction
对于 callAsFunction,只需实现名为 callAsFunction 的方法,参数和返回值可自行任意定义。
例如,考虑一个ShapeCalculator结构体:
Swift
struct ShapeCalculator {
func callAsFunction(length: Int, width: Double) -> Double {
return Double(length) * width
}
func callAsFunction(radius: Double) -> Double {
return 3.14 * radius * radius
}
func callAsFunction(side: Double) -> Double {
return side * side
}
}
使用示例
Swift
func runTest() -> Void {
let calculator = ShapeCalculator()
print("Area: \(calculator(length: 5, width: 3.0))")
print("Area: \(calculator(radius: 2.0))")
print("Area: \(calculator(side: 4.0))")
}
输出结果如下:
Swift
Area: 15.0
Area: 12.56
Area: 16.0
2:@dynamicCallable
当使用 @dynamicCallable 时,需要将此属性应用于类、结构、枚举或协议,使其类型的实例可被视为可调用函数。这要求必须实现dynamicallyCall(withArguments:)
或dynamicallyCall(withKeywordArguments:)
其中一个或两个方法。
例如,我们创建一个StringManipulator
结构体:
Swift
@dynamicCallable struct StringManipulator {
func dynamicallyCall(withArguments args: [String]) -> String {
var result = ""
for string in args {
result += string.uppercased()
}
return result
}
func dynamicallyCall(withKeywordArguments pairs: KeyValuePairs<String, String>) -> String {
var result = ""
for (key, value) in pairs {
result += "\(key): \(value.uppercased())\n"
}
return result
}
}
使用示例
Swift
func runTest() -> Void {
let manipulator = StringManipulator()
print("Result: \(manipulator("hello", "world"))")
print("Result: \(manipulator(name: "John", age: "30"))")
}
输出结果为:
Swift
Result: HELLO WORLD
Result: NAME: JOHN
AGE: 30
两者的区别
1. 参数类型要求
@dynamicCallable实现的方法调用,参数类型必须一致, 参数数量可以不一样
callAsFunction 参数类型可以不一致, 参数数量固定的
2. 方法命名要求
@dynamicCallable必须实现一个名为dynamicallyCall的方法,参数标签名称必须是withArguments或withKeywordArguments;callAsFunction必须实现一个名为callAsFunction的方法,并且参数标签可以自定义,因此callAsFunction具有更灵活的参数标签命名
3. 相同点
两者实现的方法都支持方法重载,但对于@dynamicCallable,重载方法的参数标签必须是withArguments或withKeywordArguments