Swift 带可选值的字典下标

Swift dictionary subscript with optional values

亲爱的,

这是我的可在操场上测试的代码:

import Foundation
import UIKit

enum Error : Swift.Error, LocalizedError {

    case failedTypeCastingUITableViewCell(name: String, type: Any.Type, reuseIdentifier: String?)

    var domain: String {
        return ""
    }

    var code: Int {
        return 0
    }

    var nserror : NSError {
        return NSError(domain: self.domain,
                       code: self.code,
                       userInfo: self.userInfo)
    }

//    var userInfo : [String: Any]? {
//        var userInfo : [String: Any] = [:]
//
//        switch self {
//        case .failedTypeCastingUITableViewCell(let name, let type, let reuseIdentifier):
//            userInfo = [
//                "param_name": name
//               ,"param_type": "\(type)"
//               ,"param_identifier": reuseIdentifier
//            ]
//            return userInfo
//        }
//    }

    var userInfo : [String: Any]? {
        var userInfo : [String: Any] = [:]

        switch self {
        case .failedTypeCastingUITableViewCell(let name, let type, let reuseIdentifier):
            userInfo = [
                "param_name": name
               ,"param_type": "\(type)"
            ]
            userInfo["param_identifier"] = reuseIdentifier
            return userInfo
        }
    }

}

print(Error.failedTypeCastingUITableViewCell(name: "", type: UITableViewCell.self, reuseIdentifier: nil).userInfo)

这是我从打印中得到的结果,也是我想通过注释代码实现的结果:

Optional(["param_name": "", "param_type": "UITableViewCell"])

这是我从注释代码中得到的结果:

Optional(["param_identifier": nil, "param_type": "UITableViewCell", "param_name": ""])

我知道它必须以这种方式工作,但我的问题是我可以通过某种方式摆脱它吗? IE。自定义初始化?自定义下标?

是的!只是不要为那个下标写任何东西,当你试图访问那个下标时,它会自动 return nil.

示例:

myDict: [String : Any] = [
    "key1" : 1,
    "key2" : 2
]

let emptySubscript = myDict["key3"] // this will be nil

给出具体示例,这当然是可能的,并且有多种方式。

一种方法是使用 key/value 对,并过滤掉 nil:

let kv = [
    ("param_name", name),
    ("param_type", "\(type)"),
    ("param_identifier", reuseIdentifier)
    ].filter{ != nil}.map{([=10=], !)} // <== this is your magic line

userInfo = Dictionary(uniqueKeysWithValues: kv)

另一种方法是 reduce:

userInfo = [
    ("param_name", name),
    ("param_type", "\(type)"),
    ("param_identifier", reuseIdentifier)
    ]
    .reduce(into: [:]) { (d, kv) in d[kv.0] = kv.1 }

为了提高可读性,您可以将其提取到扩展名中:

extension Dictionary {
    init<S>(uniqueKeysWithNonNilValues seq: S)
        where S : Sequence, S.Element == (Key, Value?) {
            self = seq.reduce(into: [:]) { (d, kv) in d[kv.0] = kv.1 }
    }
}

然后调用代码会非常好 IMO:

userInfo = Dictionary(uniqueKeysWithNonNilValues: [
    ("param_name", name),
    ("param_type", "\(type)"),
    ("param_identifier", reuseIdentifier)
])

但我们可以将它推得更接近您建议的语法,也许这样更好,因为它再次感觉像字典:

extension Dictionary {
    init(withNonNilValues seq: KeyValuePairs<Key, Value?>) {
        self = seq.reduce(into: [:]) { (d, kv) in d[kv.0] = kv.1 }
    }
}

userInfo = Dictionary(withNonNilValues: [
    "param_name": name,
    "param_type": "\(type)",
    "param_identifier": reuseIdentifier,
    ])