结构的closure属性是否可以引用struct实例,而没有显式引用?

时间:2016-02-04 15:52:02

标签: swift struct

这是我想做的,但数量属性不可用。

struct MyStruct {
    var quantity: Int
    let valueFn: () -> (Int)
}
var s1 = MyStruct(quantity: 2) { () -> (Int) in
    return quantity * 2 // error: can't use `quantity`
}

它不适用于类:

class MyClass {
    var quantity: Int
    let valueFn: () -> (Int)

    init(valueFn: () -> (Int)) {
        self.valueFn = valueFn
    }
}
var c1 = MyClass { () -> (Int) in
    return quantity // error: can't use quantity or self
}

这个可行,但我必须显式传入struct或struct属性。 我的问题是:如果没有第三个属性来包装并传入引用,我可以这样做吗?有更多的Swifty方法吗?

struct MyOtherStruct {
    var quantity: Int
    private let valueFn: (Int) -> (Int)
    var value: Int {
        return valueFn(quantity)
    }
}
var s3 = MyOtherStruct(quantity: 2) { (quantity) -> (Int) in
    return quantity * 2
}
s3.value // -> 4

1 个答案:

答案 0 :(得分:1)

我现在已经过去20分钟了,我不相信这可以在MyStruct个实例的初始化中实现;因为在调用到初始化器(使用上面的尾随闭包)时,实例尚不存在。不过,我将在下面展示一个类的解决方法;一个与上面的第三种方法非常相似,一种具有更多功能用法(但可怕的更糟糕的类实现),使用了子类NSObject

无论如何,上面可能会回答你的问题(对于结构," no" "可能,但过于复杂" 关于类)关于以多种方式直接使用初始化程序。

以下

  1. 封闭"包装"方法很多你的第三个解决方案:在初始化时发送的闭包上包装一个惰性闭包。这种方法的缺点是你不能为不同的类实例选择你想在闭包中使用哪个类属性,因为包装器(调用mutable初始化闭包)已经在编译时设置了。 / p>

  2. 子类化NSObject:一种对于任何实际应用而言可能过于复杂的方法(也非常不易使用),但是它可以让您更加灵活地控制在闭包中使用哪些类属性。通过继承NSObject,您可以访问方法.valueForKey以应用于self。添加了技术讨论/好奇心。

  3. 方法1

    class MyClass {
        var quantity: Int
        private let closure: (Int) -> (Int)
    
        init(quantity: Int, closure: (Int) -> (Int)) {
            self.quantity = quantity
            self.closure = closure
        }
    
        lazy var valueFn : () -> Int = {
            [unowned self] () -> Int in
            return self.closure(self.quantity)
        }
    }
    
    /* Example usage */
    var c1 = MyClass(quantity: 2) { (a) -> (Int) in
        return a * 2
    }
    
    c1.valueFn() // 4
    c1.quantity = 4
    c1.valueFn() // 8
    

    方法2

    班级设置(...):

    class MyClass : NSObject {
        var quantity: Int = 0
        var anotherQuantity: Int = 0
        private var keyExists : Bool = true
        private let key : String
        private let foo: (Int) -> Int
    
        init(operateClosureOn: (propertyWithKey: String, withInitialValue: Int),
            closure: (Int) -> Int) {
            key = operateClosureOn.propertyWithKey
            foo = closure
    
            super.init()
    
            let val = operateClosureOn.withInitialValue
            if let _ = (Mirror(reflecting: self).children.filter{ $0.label == key }).first {
                self.setValue(val, forKey: key)
            }
            else { keyExists = false }
        }
    
        lazy var valueFn: () -> Int = {
            [unowned self] () -> Int in
    
            if !self.keyExists {
                return 0
            }
    
            guard let a = self.valueForKey(self.key) as? Int else {
                print("Unexpected: property for key '\(self.key)' is not if type 'Int'.")
                return 0
            }
    
            return self.foo(a)
        }
    }
    

    使用示例:

    /* Example usage */
    var c2 = MyClass(operateClosureOn: ("quantity", 2)) {
        (val) -> Int in
        return 2 * val
    }
    
    c2.valueFn() // 4
    c2.quantity = 4
    c2.valueFn() // 8
    
    var c3 = MyClass(operateClosureOn: ("anotherQuantity", 20)) {
        (val) -> Int in
        return val / 2
    }
    
    c3.valueFn() // 10
    c3.anotherQuantity = 40
    c3.valueFn() // 20
    
    
    var c4 = MyClass(operateClosureOn: ("aTypo", 20)) {
        (val) -> Int in
        return val / 2
    }
    
    c4.valueFn() // 0, OK, at least no runtime exception with this non-safe non-swifty solution :0)