我在Swift中有以下代码:
var dictionary: [String: Any?]?
fileprivate func value(forKey key: Key) -> Any? {
if let dictionary = self.dictionary {
return dictionary[key.rawValue]
}
...
}
我收到一条警告:“任何人都隐含地强迫了表达?”去任何?'在return语句中。我在做什么错了?
答案 0 :(得分:5)
您的字典的值为Any?
。访问字典值的结果是可选的,因为键可能不存在。因此,您最终得到了Any??
。
确实不需要将字典声明为具有可选值。
将其更改为[String: Any]?
,您的问题就消失了。
答案 1 :(得分:3)
由于dictionary
子脚本值的类型为Any?
,并且字典始终将?
附加到key/value
访问权限= Any??
您可以替换
[String: Any?]?
使用
[String: Any]?
答案 2 :(得分:1)
我想举一个关于rmaddy所说的例子。
假设我们有以下代码:
var dictionary: [String: Any] = ["coco": 1, "foo": "yo"]
func value(dic: [String: Any] , forKey key: String) -> Any {
// Expression implicitly coerced from 'Any?' to 'Any'
return dictionary[key]
}
// Optional(1)
print(value(dic: dictionary, forKey: "coco"))
一开始,即使我们不声明任何可选值,字典也不知道键是否确实存在。 因此,您可以更好地理解为什么还有另一个意想不到的可选值。
答案 3 :(得分:1)
似乎没有人真正解释错误消息,所以我将继续进行操作。
假设您有一个整数i
,我将其表示为下图:
let i = 123
// ┏━━━━━━━━━━━━┓
// ┃ Name: i ┃
// ┃ Type: Int ┃
// ┠────────────┨
// ┃ Value: 123 ┃
// ┗━━━━━━━━━━━━┛
Any
您可以将i
“装箱”为类型Any
的值。此容器“隐藏” Int
的{{1}}。
i
或"s"
)一起处理。true
类型的值确实可以做很多事情。由于Any
的范围如此广泛,因此它并不能真正说明您可以使用该值做的事情。您不能像Any
那样.lowercased()
,不能像String
那样toggle()
,只能做的就是传递它,最后向下传递-将其转换为可以执行更多操作的另一种类型。将Bool
装箱成i
时,看起来像这样:
Any
let any123 = i as Any
// ┏━━━━━━━━━━━━━━━━━━┓
// ┃ Name: any123 ┃
// ┃ Type: Any ┃
// ┠──────────────────┨
// ┃ Value: ┃
// ┃ ┏━━━━━━━━━━━━┓ ┃
// ┃ ┃ Name: i ┃ ┃
// ┃ ┃ Type: Int ┃ ┃
// ┃ ┠────────────┨ ┃
// ┃ ┃ Value: 123 ┃ ┃
// ┃ ┗━━━━━━━━━━━━┛ ┃
// ┗━━━━━━━━━━━━━━━━━━┛
对于类型系统是“不透明的”,例如,类型系统无法确定Any
框边界之外的内容(这就是为什么我用实心轮廓表示它的原因)。 / p>
Any
可选的是具有两种情况的通用枚举,Optional<T>
(存储称为some
的关联值)和wrapped
(不包含)。它在任何类型的none
上都是通用的,但是出于本示例的目的,我将仅讨论T
为T
的情况,因此Int
也称为{{ 1}}。
Optional<Int>
是任何类型Int?
的{{1}}缩写。
nil
与Optional<T>.none
不同,optional对类型系统是“透明的”(这就是为什么我用虚线轮廓表示它的原因)。您始终可以在其中看到值的类型。
可选组件可以相互组合,就像俄罗斯嵌套娃娃一样:
T
例如,当您尝试下标存储let some123: Int? = 123 // implicitly wraps the value into an optional
let none: Int? = nil
// ┏╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┓ ┏╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┓
// ╏ Name: some123 ╏ ╏ Name: none ╏
// ╏ Type: Int ╏ ╏ Type: Int? ╏
// ┠──────────────────┨ ┠───────────────┨
// ╏ Case: .some ╏ ╏ Case: .none ╏
// ╏ wrapped: ╏ ┗╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┛
// ╏ ┏━━━━━━━━━━━━┓ ╏
// ╏ ┃ Name: i ┃ ╏
// ╏ ┃ Type: Int ┃ ╏
// ╏ ┠────────────┨ ╏
// ╏ ┃ Value: 123 ┃ ╏
// ╏ ┗━━━━━━━━━━━━┛ ╏
// ┗╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┛
值的字典时,会发生这种情况。有3种可能的结果:
Any
。就像
let someSome123: Int?? = 123 // Shorthand for Optional<Optional<Int>>.some(Optional<Int>.some(123))
let someOfNone: Int?? = .some(nil) // Shorthand for Optional<Optional<Int>>.some(Optional<Int>.none)
let none: Int?? = nil // Shorthand for Optional<Optional<Int>>.none
// ┏╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┓ ┏╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┓ ┏╍╍╍╍╍╍╍╍╍╍╍╍╍┓
// ╏ Name: someSome123 ╏ ╏ Name: someOfNone ╏ ╏ Name: none ╏
// ╏ Type: Int?? ╏ ╏ Type: Int?? ╏ ╏ Type: Int?? ╏
// ┠────────────────────────┨ ┠───────────────────┨ ┠─────────────┨
// ╏ Case: .some ╏ ╏ Case: .some ╏ ╏ Case: .none ╏
// ╏ wrapped: ╏ ╏ wrapped: ╏ ┗╍╍╍╍╍╍╍╍╍╍╍╍╍┛
// ╏ ┏╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┓ ╏ ╏ ┏╍╍╍╍╍╍╍╍╍╍╍╍╍┓ ╏
// ╏ ╏ Type: Int? ╏ ╏ ╏ ╏ Type: Int? ╏ ╏
// ╏ ┠──────────────────┨ ╏ ╏ ┠─────────────┨ ╏
// ╏ ╏ Case: .some ╏ ╏ ╏ ╏ Case: .none ╏ ╏
// ╏ ╏ wrapped: ╏ ╏ ╏ ┗╍╍╍╍╍╍╍╍╍╍╍╍╍┛ ╏
// ╏ ╏ ┏━━━━━━━━━━━━┓ ╏ ╏ ┗╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┛
// ╏ ╏ ┃ Type: Int ┃ ╏ ╏
// ╏ ╏ ┠────────────┨ ╏ ╏
// ╏ ╏ ┃ Value: 123 ┃ ╏ ╏
// ╏ ╏ ┗━━━━━━━━━━━━┛ ╏ ╏
// ╏ ┗╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┛ ╏
// ┗╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┛
一样
T?
。就像上面的常量nil
someSome123
许多语言都允许所有类型存储nil
值。这是一个较弱的设计,因为它无法区分#2和#3。 “这someOfNone
表示值不存在,还是值存在,但值本身是none
?”可选内容的可嵌套性允许这种区别。还有很多其他可能的情况,例如访问null
的{{1}}值。
null
和null
就像可选内容如何包含可选内容一样,可选内容可以包含类型first
的值,反之亦然。以下是重新生成错误的示例:
Array<Optional<T>>
如您所见,Any
和Optional
都包含两层可选性和一层类型擦除(由Any
提供)。存在此警告是为了告诉您,通过将let any123: Any = 123
let optionalOptionalAny123: Any?? = any123
let optionalAny123: Any? = optionalOptionalAny // ⚠️ warning: expression implicitly coerced from 'Any??' to 'Any?'
// ┏╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┓ ┏╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┓
// ╏ Name: optionalOptionalAny123 ╏ ╏ Name: optionalAny123 ╏
// ╏ Type: Optional<Optional<Any>> ╏ ╏ Type: Optional<Any> ╏
// ┠───────────────────────────────┨ ┠──────────────────────────────────┨
// ╏ Case: .some ╏ ╏ Case: .some ╏
// ╏ wrapped: ╏ ╏ wrapped: ╏
// ╏ ┏╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┓ ╏ ╏ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ╏
// ╏ ╏ Type: Optional<Any> ╏ ╏ ╏ ┃ Type: Any ┃ ╏
// ╏ ┠───────────────────────┨ ╏ ╏ ┠────────────────────────────┨ ╏
// ╏ ╏ Case: .some ╏ ╏ ╏ ┃ Value: ┃ ╏
// ╏ ╏ wrapped: ╏ ╏ ╏ ┃ ┏╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┓ ┃ ╏
// ╏ ╏ ┏━━━━━━━━━━━━━━━━━┓ ╏ ╏ ╏ ┃ ╏ Name: some123 ╏ ┃ ╏
// ╏ ╏ ┃ Name: any123 ┃ ╏ ╏ ╏ ┃ ╏ Type: Optional<Int> ╏ ┃ ╏
// ╏ ╏ ┃ Type: Any ┃ ╏ ╏ ╏ ┃ ┠─────────────────────┨ ┃ ╏
// ╏ ╏ ┠─────────────────┨ ╏ ╏ ╏ ┃ ╏ Case: .some ╏ ┃ ╏
// ╏ ╏ ┃ Value: ┃ ╏ ╏ ╏ ┃ ╏ wrapped: ╏ ┃ ╏
// ╏ ╏ ┃ ┏━━━━━━━━━━━┓ ┃ ╏ ╏ ╏ ┃ ╏ ┏━━━━━━━━━━━┓ ╏ ┃ ╏
// ╏ ╏ ┃ ┃ i: Int ┃ ┃ ╏ ╏ ╏ ┃ ╏ ┃ i: Int ┃ ╏ ┃ ╏
// ╏ ╏ ┃ ┠───────────┨ ┃ ╏ ╏ ╏ ┃ ╏ ┠───────────┨ ╏ ┃ ╏
// ╏ ╏ ┃ ┃ Value: 123┃ ┃ ╏ ╏ ╏ ┃ ╏ ┃ Value: 123┃ ╏ ┃ ╏
// ╏ ╏ ┃ ┗━━━━━━━━━━━┛ ┃ ╏ ╏ ╏ ┃ ╏ ┗━━━━━━━━━━━┛ ╏ ┃ ╏
// ╏ ╏ ┗━━━━━━━━━━━━━━━━━┛ ╏ ╏ ╏ ┃ ┗╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┛ ┃ ╏
// ╏ ┗╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┛ ╏ ╏ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ╏
// ┗╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┛ ┗╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┛
强制为optionalOptionalAny123
,您将掩盖optionalAny123
隐藏面纱后面的第二层可选性。
要解决此警告,您可以遵循以下三个建议之一:
提供默认值以避免出现此警告
通过展开其内容或使用默认值Any
来剥离一层可选内容。这很少是一个好主意,因为很少存在明智的默认值。
Any??
强制展开该值以避免发生此警告
通过强行展开一层可选层。这很少是一个好主意,因为它要求您绝对确定自己没有Any?
。
Any
明确地投射为“任何人?”与“任意”一样?消除此警告
您可以按原样保留值(具有2个可选层),将可选层之一隐藏在nil
的面纱之后。在运行时添加let optionalAny123: Any? = optionalOptionalAny ?? 0
实际上没有任何作用。这是语法语法,表示您有意要此行为,而不是误解它。
nil
理想情况下,您应该尽快平整可选性。如果可选的嵌套在您的系统中具有某种意义,请尽快对此采取行动,并在此后不久将其扁平化。