Swift Expression从“ Any ??”隐式强制去任何?'

时间:2019-07-11 16:14:54

标签: swift

我在Swift中有以下代码:

 var dictionary: [String: Any?]? 

 fileprivate func value(forKey key: Key) -> Any? {
    if let dictionary = self.dictionary {
        return dictionary[key.rawValue]
    }

     ...
 }

我收到一条警告:“任何人都隐含地强迫了表达?”去任何?'在return语句中。我在做什么错了?

4 个答案:

答案 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上都是通用的,但是出于本示例的目的,我将仅讨论TT的情况,因此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种可能的结果:

  1. 密钥存在一个值,并且该值不是Any。就像
  2. 上面的常量 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 ┃ ╏ ╏ // ╏ ╏ ┗━━━━━━━━━━━━┛ ╏ ╏ // ╏ ┗╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┛ ╏ // ┗╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┛ 一样
  3. 该键存在一个值,但值为T?。就像上面的常量nil
  4. 该键不存在任何值。就像上面的常量someSome123

许多语言都允许所有类型存储nil值。这是一个较弱的设计,因为它无法区分#2和#3。 “这someOfNone表示值不存在,还是值存在,但值本身是none?”可选内容的可嵌套性允许这种区别。还有很多其他可能的情况,例如访问null的{​​{1}}值。

组成nullnull

就像可选内容如何包含可选内容一样,可选内容可以包含类型first的值,反之亦然。以下是重新生成错误的示例:

Array<Optional<T>>

如您所见,AnyOptional都包含两层可选性和一层类型擦除(由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隐藏面纱后面的第二层可选性。

要解决此警告,您可以遵循以下三个建议之一:

  1.   

    提供默认值以避免出现此警告

    通过展开其内容或使用默认值Any来剥离一层可选内容。这很少是一个好主意,因为很少存在明智的默认值。

    Any??
  2.   

    强制展开该值以避免发生此警告

    通过强行展开一层可选层。这很少是一个好主意,因为它要求您绝对确定自己没有Any?

    Any
  3.   

    明确地投射为“任何人?”与“任意”一样?消除此警告

    您可以按原样保留值(具有2个可选层),将可选层之一隐藏在nil的面纱之后。在运行时添加let optionalAny123: Any? = optionalOptionalAny ?? 0 实际上没有任何作用。这是语法语法,表示您有意要此行为,而不是误解它。

    nil

理想情况下,您应该尽快平整可选性。如果可选的嵌套在您的系统中具有某种意义,请尽快对此采取行动,并在此后不久将其扁平化。