Swift 3型推理混淆

Swift 3型推理混淆,swift,macos,swift3,Swift,Macos,Swift3,我在用macOS 我有以下代码。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

我在用macOS

我有以下代码。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不?

SWIFT 3去除了SWIFT和基础类型之间的隐式铸造(<代码> int <代码> > >代码> nStuts<代码>。code>let a=20给出
a
类型
Int
,您需要使用
a作为NSNumber
手动将其转换为
NSNumber
。另一方面,您的第一行编译是因为
20
推断出预期的
NSNumber
类型

或者,您可以为
a
指定
NSNumber
类型以开始使用

let a: NSNumber = 20
之后,您可以在需要
NSNumber
的地方使用它

我不知道为什么你的第五行没有编译-这可能是一个bug。

更新的答案-适用于macOS

使用XCODE 8 beta 6,SWIFT不再隐式将SWIFT值类型桥接到基础类类型。这意味着如果一个函数需要一个

NSNumber
,并且您向它传递了一个
Int
变量,那么您必须显式地将它强制转换为
NSNumber
。对于整型文字而言,这不是必需的,因为Swift仍将正确推断类型

为什么1编译,而2不编译

1之所以编译,是因为Swift能够推断
20
的类型为
NSNumber
,因此
[“a”:20]
作为
[字符串:NSNumber]
工作

2不编译,因为
a
的类型已被确定为
Int
,因此需要将其显式转换为
NSNumber
。Xcode的修复建议使用
NSNumber(a)
,但遗憾的是,它无法编译。使用
NSNumber(值:a)
a作为NSNumber

为什么2和3有不同的错误消息

对于2,您提供了一个字典文本
[“a”:a]
,因此Swift检查每个键和值的类型,看看它是否与它期望的字典类型匹配。由于
a
Int
且值是
NSNumber
,因此出现错误无法将“Int”类型的值转换为预期的字典值类型“NSNumber”。它希望您提供转换

对于3,您提供的变量类型为
[String,Int]
。Swift告诉您,它无法将其转换为
[String,NSNumber]
。它可以,但由于Xcode 8 beta 6中的更改,没有显式强制转换是不行的

为什么4编译,而5不编译

4编译,因为您现在提供了3所缺少的对
[String:NSNumber]
的显式转换

5不会编译,因为您再次提供了字典文本,Swift检查每个键和值以确保它们是正确的类型。在没有显式转换的情况下,它不会将
Int
转换为
NSNumber
,因此这里的错误是无法将“Int”类型的值转换为预期的字典值类型“NSNumber”。关键是,当您将字典文本转换为字典类型时,Swift不会转换字典文本的单个键和值。你必须为每一个直接提供该类型


先前的答案-适用于iOS 对于Xcode 8 beta 6,参数的类型
metrics
已更改为
[String:Any]?
。现在,前4个示例已编译,第5个示例未编译。你的前两个问题不再有效。剩下的唯一问题是:

为什么4编译,而5不编译

语句4(
met作为[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

有两种方法可以让斯威夫特快乐:

["a": NSNumber(value: a)] as [String: NSNumber]
["a": a as NSNumber] as [String: NSNumber]
当然,现在在这两种情况下,字典文本都可以推断为
[String:NSNumber]
,因此不需要强制转换


另外,由于
度量标准
现在是
[String:Any]
,当
[String:Int]
可以时,将
[a:a]
转换为
[String:NSNumber]
是没有意义的。

我使用的是Xcode8b6。度量参数的类型为“[String:NSNumber]”。这些错误消息来自Xcode 8b6,因此所有问题都是有效的。您是否在macOS上开发?似乎iOS和macOS是不同的。是的,我应该提到这一点。我在macOS上。我不知道iOS和macOS是不同的。我想我还是很困惑。为什么我们之间的行为有差异