Swift 3 类型推断混乱
Swift 3 type inference confusion
我正在使用 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 和 Foundation 类型之间的隐式转换(在本例中为 Int
-> NSNumber
)。 let a = 20
为 a
提供 Int
类型,您需要使用 a as NSNumber
手动将其转换为 NSNumber
。另一方面,您的第一行编译是因为 20
推断出预期的 NSNumber
类型。
或者,您可以给 a
NSNumber
类型以开始使用
let a: NSNumber = 20
之后您可以在需要 NSNumber
的地方使用它。
我不确定为什么你的第五行没有编译 - 这可能是一个错误。
更新的答案 - 适用于 macOS
使用 Xcode 8 beta 6,Swift 不再隐式桥接 Swift 值类型到基础 class 类型。这意味着如果一个函数需要一个 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(value: a)
或 a as NSNumber
.
Why do 2 and 3 have different error messages?
对于 2,您提供的是字典文字 ["a": a]
,因此 Swift 检查每个键和值的类型,看它是否与它期望的字典类型相匹配。因为 a
是一个 Int
并且值是一个 NSNumber
,你会得到错误 Cannot convert value of type 'Int' to expected dictionary value type 'NSNumber'。它希望您提供转换。
对于 3,您提供了 [String, Int]
类型的变量。 Swift 告诉您它无法将其转换为 [String, NSNumber]
。它可以,但由于 Xcode 8 beta 6.
中的更改,它不能没有显式转换
Why does 4 compile, but 5 does not?
4 可以编译,因为您现在向 [String: NSNumber]
提供了 3 所缺少的显式转换。
5 无法编译,因为您再次提供字典文字,并且 Swift 检查每个键和值以确保它们是正确的类型。如果没有显式转换,它不会将 Int
转换为 NSNumber
,因此这里的错误是 无法将类型 'Int' 的值转换为预期的字典值类型 'NSNumber'。关键是 Swift 在将字典文字转换为字典类型时不会转换字典文字的各个键和值。您必须直接为每个演员提供演员表。
上一个答案 - iOS
在 Xcode 8 beta 6 中,参数类型 metrics
已更改为 [String: Any]?
。现在,前 4 个示例编译,第 5 个不编译。您的前两个问题不再有效。剩下的唯一问题是:
Why does 4 compile, but 5 does not?
语句 4 (met as [String: NSNumber]
) 可以编译,因为 met
的类型为 [String: Int]
,并且 Swift 可以将 [String: Int]
转换为 [String: NSNumber]
。在这种情况下,它正在查看整个字典。 Swift 知道如何将 Int
转换为 NSNumber
,但除非您明确要求它这样做,否则它不会这样做。在这种情况下,由于您要呈现 [String: Int]
类型的字典并要求它将其转换为 [String: NSNumber]
,因此您要求它将 Int
转换为 NSNumber
。
在语句 5 中,您将字典文字 ["a": a]
转换为字典类型 as [String: NSNumber]
。错误信息是:
无法将类型 'Int' 的值转换为预期的字典值类型 'NSNumber'
在这种情况下,Swift 正在查看各个类型,检查 "a"
是 String
而 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]
,因此不需要强制转换。
此外,由于 metrics
现在是 [String: Any]
,因此将 ["a": a]
转换为 [String: NSNumber]
是没有意义的,而 [String: Int]
可以。
我正在使用 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 和 Foundation 类型之间的隐式转换(在本例中为 Int
-> NSNumber
)。 let a = 20
为 a
提供 Int
类型,您需要使用 a as NSNumber
手动将其转换为 NSNumber
。另一方面,您的第一行编译是因为 20
推断出预期的 NSNumber
类型。
或者,您可以给 a
NSNumber
类型以开始使用
let a: NSNumber = 20
之后您可以在需要 NSNumber
的地方使用它。
我不确定为什么你的第五行没有编译 - 这可能是一个错误。
更新的答案 - 适用于 macOS
使用 Xcode 8 beta 6,Swift 不再隐式桥接 Swift 值类型到基础 class 类型。这意味着如果一个函数需要一个 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(value: a)
或 a as NSNumber
.
Why do 2 and 3 have different error messages?
对于 2,您提供的是字典文字 ["a": a]
,因此 Swift 检查每个键和值的类型,看它是否与它期望的字典类型相匹配。因为 a
是一个 Int
并且值是一个 NSNumber
,你会得到错误 Cannot convert value of type 'Int' to expected dictionary value type 'NSNumber'。它希望您提供转换。
对于 3,您提供了 [String, Int]
类型的变量。 Swift 告诉您它无法将其转换为 [String, NSNumber]
。它可以,但由于 Xcode 8 beta 6.
Why does 4 compile, but 5 does not?
4 可以编译,因为您现在向 [String: NSNumber]
提供了 3 所缺少的显式转换。
5 无法编译,因为您再次提供字典文字,并且 Swift 检查每个键和值以确保它们是正确的类型。如果没有显式转换,它不会将 Int
转换为 NSNumber
,因此这里的错误是 无法将类型 'Int' 的值转换为预期的字典值类型 'NSNumber'。关键是 Swift 在将字典文字转换为字典类型时不会转换字典文字的各个键和值。您必须直接为每个演员提供演员表。
上一个答案 - iOS
在 Xcode 8 beta 6 中,参数类型 metrics
已更改为 [String: Any]?
。现在,前 4 个示例编译,第 5 个不编译。您的前两个问题不再有效。剩下的唯一问题是:
Why does 4 compile, but 5 does not?
语句 4 (met as [String: NSNumber]
) 可以编译,因为 met
的类型为 [String: Int]
,并且 Swift 可以将 [String: Int]
转换为 [String: NSNumber]
。在这种情况下,它正在查看整个字典。 Swift 知道如何将 Int
转换为 NSNumber
,但除非您明确要求它这样做,否则它不会这样做。在这种情况下,由于您要呈现 [String: Int]
类型的字典并要求它将其转换为 [String: NSNumber]
,因此您要求它将 Int
转换为 NSNumber
。
在语句 5 中,您将字典文字 ["a": a]
转换为字典类型 as [String: NSNumber]
。错误信息是:
无法将类型 'Int' 的值转换为预期的字典值类型 'NSNumber'
在这种情况下,Swift 正在查看各个类型,检查 "a"
是 String
而 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]
,因此不需要强制转换。
此外,由于 metrics
现在是 [String: Any]
,因此将 ["a": a]
转换为 [String: NSNumber]
是没有意义的,而 [String: Int]
可以。