美文网首页
Swift @dynamicMemberLookup和@dyna

Swift @dynamicMemberLookup和@dyna

作者: LonnieQ | 来源:发表于2020-09-20 20:04 被阅读0次

在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

相关文章

网友评论

      本文标题:Swift @dynamicMemberLookup和@dyna

      本文链接:https://www.haomeiwen.com/subject/nmupyktx.html