我有以下代码. 1,2,3,4和5之间的唯一区别是’metrics’参数中的内容.
let a = 20 let met = ["a": a] // 1: This compiles. _ = NSLayoutConstraint.constraints(withVisualFormat: "|[v1(a)]|", metrics: ["a": 20], views: ["v1": v1]) // 2: This fails with "Cannot convert value of type 'Int' to expected dictionary value type 'NSNumber'". _ = NSLayoutConstraint.constraints(withVisualFormat: "|[v1(a)]|", metrics: ["a": a], views: ["v1": v1]) // 3: This fails with "Cannot convert value of type '[String: Int]' to expected argument type '[String: NSNumber]?'". _ = NSLayoutConstraint.constraints(withVisualFormat: "|[v1(a)]|", metrics: met, views: ["v1": v1]) // 4: This compiles. _ = NSLayoutConstraint.constraints(withVisualFormat: "|[v1(a)]|", metrics: met as [String: NSNumber]?, views: ["v1": v1]) // 5: This fails with "Cannot convert value of type 'Int' to expected dictionary value type 'NSNumber'". _ = NSLayoutConstraint.constraints(withVisualFormat: "|[v1(a)]|", metrics: ["a": a] as [String: NSNumber]?, views: ["v1": v1])
为什么1编译,但2不编译?
为什么2和3有不同的错误消息?
为什么4编译,但5不编译?
更新的答案 – 对于macOS使用Xcode 8 beta 6,Swift不再隐式地将Swift值类型与Foundation类类型联系起来.这意味着如果函数期望NSNumber并且您将其传递给Int变量,则必须将其显式地转换为NSNumber.这对于整数文字不是必需的,因为Swift仍然会正确地推断出类型.
Why does 1 compile, but 2 does not?
1编译,因为Swift能够将20的类型推断为NSNumber,因此[“a”:20]用作[String:NSNumber].
2不编译,因为a的类型已经建立为Int,所以你需要显式转换为NSNumber. Xcode的修复 – 它暗示了NSNumber(a),但遗憾的是它没有编译.使用NSNumber(值:a)或a作为NSNumber.
Why do 2 and 3 have different error messages?
对于2,您提供字典文字[“a”:a],因此Swift检查每个键和值的类型,以查看它是否与它期望的字典类型匹配.由于a是Int并且值是NSNumber,因此您会收到错误无法将“Int”类型的值转换为预期的字典值类型“NSNumber”.它希望您提供转换.
对于3,您提供的类型为[String,Int]的变量. Swift告诉你它无法将其转换为[String,NSNumber].由于Xcode 8 beta 6的变化,它可以,但不是没有明确的演员.
Why does 4 compile, but 5 does not?
4编译,因为你现在提供3缺少的[String:NSNumber]显式强制转换.
5不编译,因为你再次提供字典文字,Swift检查每个键和值,以确保它们是正确的类型.如果没有显式强制转换,它不会将Int转换为NSNumber,因此这里的错误是无法将’Int’类型的值转换为预期的字典值类型’NSNumber’.关键是当您将字典文字强制转换为字典类型时,Swift不会强制转换字典文字的各个键和值.您必须直接为每个人提供该演员表.
上一个答案 – 适用于iOS
使用Xcode 8 beta 6,参数指标的类型已更改为[String:Any]?.现在,前4个示例编译,而第5个没有编译.您的前两个问题不再有效.剩下的唯一问题是:
Why does 4 compile, but 5 does not?
语句4(遇到[String:NSNumber])编译因为met有类型[String:Int]而Swift可以将[String:Int]转换为[String:NSNumber].在这种情况下,它正在查看整个字典. Swift知道如何将Int转换为NSNumber,但如果没有要求它明确地这样做,它就不会这样做.在这种情况下,由于您要呈现[String:Int]类型的字典并要求它将其转换为[String:NSNumber],因此您要求它将Int转换为NSNumber.
在语句5中,您将字典文字[“a”:a]转换为字典类型为[String:NSNumber].错误消息是:
无法将“Int”类型的值转换为预期的字典值类型“NSNumber”
在这种情况下,Swift正在查看各个类型,检查“a”是字符串而a是NSNumber.将字典文字强制转换为类型不会将每个键和值显式地转换为相应的类型.在这种情况下,你只是提出它们并说它们已经是那种类型了.由于Xcode 8 beta 6的新变化,Swift将不再隐式地将Swift值类型转换为桥接基础类型.因此Swift希望您将Int a显式转换为NSNumber.
有两种方法让Swift高兴:
["a": NSNumber(value: a)] as [String: NSNumber] ["a": a as NSNumber] as [String: NSNumber]
当然,现在在两种情况下,字典文字都可以推断为[String:NSNumber],因此不需要演员.
此外,由于度量现在是[String:Any],当[String:Int]执行时,将[“a”:a]转换为[String:NSNumber]是没有意义的.