在Swift语言中,我们定义一个类型的时候,在这类型前添加@dynamicMemberLookup
语法,通过实现subscript<T>(dynamicMember member: String)
下标方法,就可以让我们在保留着编译语言的速度的前提下实现Python等语言的动态特性。 以下用一些例子说明。
定义JSONObject
@dynamicMemberLookup
class JSONObject {
var value = [String: Any]()
init(_ value: [String: Any] = [:]) {
self.value = value
}
subscript<T>(dynamicMember member: String) -> T? where T: Any {
get {
value[member] as? T
}
set {
value[member] = newValue
}
}
}
var jsonObject = JSONObject([
"a": 1,
"b": 2.2,
"c": "hello"
])
var a: Int? = jsonObject.a
var b: Double? = jsonObject.b
var c: String? = jsonObject.c
print(a, b, c)
// 1, 2.2, "hello"
jsonObject.a = 55
jsonObject.b = 66.6
jsonObject.c = "world"
a = jsonObject.a
b = jsonObject.b
c = jsonObject.c
print(a, b, c)
// 55, 66.6, "world"
我们不仅可以添加基本数据类型,还可以添加方法。
自定义Math对象
@dynamicMemberLookup
class Math {
var params = [String: Any]()
subscript(dynamicMember member: String) -> (Double) -> (Double) {
get {
params[member] as! ((Double)->(Double))
}
set {
params[member] = newValue
}
}
subscript(dynamicMember member: String) -> (Double, Double) -> (Double) {
get {
params[member] as! ((Double, Double)->(Double))
}
set {
params[member] = newValue
}
}
}
let math = Math()
math.add = { $0 + $1 }
math.minus = { $0 - $1 }
math.multiply = { $0 * $1 }
math.divide = { $0 / $1 }
math.negate = { -$0 }
math.sin = { sin($0) }
math.cos = { cos($0) }
math.tan = { tan($0) }
print(math.add(2, 3)) // 5.0
print(math.minus(11, 4)) // 7.0
print(math.multiply(33, 3)) // 99.0
print(math.divide(44, 4)) // 11.0
print(math.negate(5)) // -5
print(math.sin(.pi / 3)) // 0.8660254037844386
print(math.cos(.pi / 3)) // 0.5000000000000001
print(math.tan(.pi / 3)) // 1.7320508075688767
一个类型实现了@dynamicCallable
语法可以动态地调用参数,只需要实现func dynamicallyCall(withKeywordArguments args: KeyValuePairs<String, Any>)
函数。比如现在改造一下JSONObject
, 可以添加一个初始化函数,传入不同的参数。
@dynamicMemberLookup
@dynamicCallable
class JSONObject {
static var new: Self { Self() }
public var value = [String: Any]()
required init(_ value: [String: Any] = [:]) {
self.value = value
}
func dynamicallyCall(withKeywordArguments args: KeyValuePairs<String, Any>) -> Self {
for item in args {
value[item.0] = item.1
}
return self
}
subscript<T>(dynamicMember member: String) -> T where T: Any {
get {
value[member] as! T
}
set {
value[member] = newValue
}
}
}
let dog = JSONObject.new(name: "Tom", age: 11, weight: 33.3)
let name: String = dog.name
let age: Int = dog.age
let weight: Double = dog.weight
print(name) // Tom
print(age) // 11
print(weight) // 33.3
网友评论