【问题标题】:How to declare dictionary with functions as values and keyed by integer?如何将函数声明为值并以整数为键的字典?
【发布时间】:2016-06-30 18:06:37
【问题描述】:
struct Test {
    func isOk () -> Bool{
        return true
    }

    var mapping: [Int: () -> Bool] = [
        1: isOk
    ]

    func test() -> Bool {
        return mapping[1]()
    }
}

我收到了这个错误:

Cannot convert value of type '(Test) -> () -> Bool' to expected dictionary value type '() -> Bool'

有什么想法吗?谢谢!

【问题讨论】:

    标签: swift function dictionary swift2


    【解决方案1】:

    您看到这种奇怪的类型 ((Test) -> () -> Bool) 是因为 Swift instance methods are curried functions

    如果将isOk 设为静态方法是可以接受的,您可以这样做:

    struct Test {
        static func isOk() -> Bool { //Make it static
            return true
        }
    
        var mapping: [Int : () -> Bool] = [
            1 : Test.isOk // Static method must be qualified by its parent type
        ]
    
        func test() -> Bool { //Bool return value necessary
            //TODO: remove force unwrapping.
            return mapping[1]!() //subscripting a Dict might return nil
        }
    }
    

    如果isOk 必须保留为实例方法,您可以这样做:

    struct Test {
        func isOk() -> Bool {
            return true
        }
    
        var mapping: [Int : (Test) -> () -> Bool] = [ //change type
            1 : isOk
        ]
    
        //the instance method received from the dict needs an instance to act on
        func test(instance: Test) -> Bool { //Bool return value necessary
            //TODO: remove force unwrapping.
            return mapping[1]!(instance)() //curried function call
        }
    }
    

    【讨论】:

      【解决方案2】:

      @AMomchilov 完全正确地解释了为什么会发生这种情况。在静态范围内(例如在mapping 的默认值赋值中),instance methods are curried functions – 意味着它们返回一个函数,该函数将给定实例作为参数进行操作,而不是隐式操作 self(如 @ 987654325@ 不引用静态范围内的实例)。

      如果您不想将isOk 设为静态方法并希望mapping 保持为[Int : () -> Bool],则另一个可能的解决方案是将其设为lazy。这将允许您在mapping 的分配中访问isOk,因为它现在处于实例范围内——因此意味着函数类型将为() -> Bool

      struct Test {
          func isOk () -> Bool {
              return true
          }
      
          lazy var mapping: [Int: () -> Bool] = [
              1 : self.isOk
          ]
      
          mutating func test() -> Bool {
              // you need to think about situations where mapping[1] returns nil
              // and deal with it in a more proper way than force unwrapping
              return mapping[1]!()
          }
      }
      

      这种方法的唯一警告是您需要将test() 标记为mutating——因为lazy 变量的默认值将在第一次访问它时设置,从而改变结构.

      虽然一个可能更简洁的替代方案(取决于用例),只是将您的函数分配给初始化程序中的字典(或字典本身)。这将允许您保持mapping 非懒惰,因此意味着test 不必是mutating

      struct Test {
          func isOk () -> Bool {
              return true
          }
      
          init() {
              mapping[1] = isOk
          }
      
          var mapping = [Int: () -> Bool]()
      
          func test() -> Bool {
              // you need to think about situations where mapping[1] returns nil
              // and deal with it in a more proper way than force unwrapping
              return mapping[1]!()
          }
      }
      

      同样,这可确保您在将方法分配给字典时处于实例范围内,从而确保它具有签名 () -> Bool

      【讨论】:

      • 我会使用 mapping[1]?() 而不是 mapping[1]!(),因为这样会更安全。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-25
      • 1970-01-01
      • 2021-05-30
      • 2014-12-21
      • 2015-07-12
      • 2012-10-19
      相关资源
      最近更新 更多