Dictionary <string,any>的替代?

时间:2017-02-21 07:45:51

标签: swift swift3

我知道我的词典将是<String,String>或者它将是<String,NSNumber>,有没有什么方法可以在声明时告诉Swift编译器,而不是声明<String,Any>还是<String,AnyObject>

4 个答案:

答案 0 :(得分:2)

enum Either<L, R> {
    case left(L)
    case right(R)

    init(_ left: L) {
        self = .left(left)
    }

    init(_ right: R) {
        self = .right(right)
    }

    init?(_ any: Any) {
        if let left = any as? L {
            self = .left(left)
        } else if let right = any as? R {
            self = .right(right)
        } else {
            return nil
        }
    }
}

然后将您的字典声明为<String, Either<String, NSNumber>>

或者如果您喜欢硬编码类型:

enum StringOrNumber {
    case string(String)
    case number(NSNumber)

    init(string: String) {
        self = .string(string)
    }

    init(number: NSNumber) {
        self = .number(number)
    }

    init?(any: Any) {
        if let string = any as? String {
            self = .string(string)
        } else if let number = any as? NSNumber {
            self = .number(number)
        } else {
            return nil
        }
    }
}

字典将是<String, StringOrNumber>

编辑:如果您的词典本身只能包含所有 String所有 NSNumber值,类型应为Either<[String: String], [String: NSNumber]>

答案 1 :(得分:2)

您可以创建一个空协议,并使String和NSNumber符合它。

protocol StringOrNumber {}

extension String:StringOrNumber {}
extension NSNumber:StringOrNumber {}

显式添加Int,Float和Double

可能会有所帮助
extension Int:StringOrNumber {}
extension Float:StringOrNumber {}
extension Double:StringOrNumber {}

然后你可以创建一个包含字符串和数字的字典

var dict:[String:StringOrNumber] = ["a":1, "b": 3.2,"c": "c"]

dict["d"] = "a string"
dict["e"] = 1.3 

但你不能添加不是字符串或数字的东西

dict["f"] = Date() //error: Cannot assign value of type 'Date' to type 'StringOrNumber?'

答案 2 :(得分:0)

扩展user28434的答案,你可以模仿C联盟类型的行为,因为它服务于&#34;或者&#34;情况最好,互相排斥。

联盟的Swift实现可能看起来很丑陋:

enum StringOrNum {
    case a(String)
    case b(NSNumber)

    var a: String {
        switch(self)
        {
        case .a(let stringValue): return stringValue
        case .b(let nsnumberValue): return String(format:"%f", nsnumberValue.doubleValue)
        }
    }

    var b: NSNumber {
        switch(self)
        {
        case .a(let stringValue): if let intValue = Int(stringValue) {
                                      return NSNumber(value: intValue)
                                  }
                                  else {
                                      return NSNumber(value: 0)    // default case
                                  }
        case .b(let nsnumberValue): return nsnumberValue
        }
    }
}

然后将字典声明为Dictionary<String, StringOrNum>

答案 3 :(得分:-1)

这会对你有帮助吗?

func myFoo<T>(dic: [String: T]) {

    if dic["Key"] is String {
        print("The value is String --> \(dic["Key"])")
    }

    if dic["Key"] is Int {
        print("The value is Int --> \(dic["Key"])")
    }
}

myFoo(dic: ["Key": 0])
myFoo(dic: ["Key": "Value"])