Быстрое выражение неявно вызвано из «Any ??» любому?' - PullRequest
1 голос
/ 11 июля 2019

У меня есть этот код в Swift:

 var dictionary: [String: Any?]? 

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

     ...
 }

Я получаю предупреждение «Выражение неявно приведено из« Any ?? »любому?'в ответном заявлении ".Что я делаю не так?

Ответы [ 4 ]

5 голосов
/ 11 июля 2019

Значение вашего словаря Any?. Результат доступа к значению словаря является необязательным, поскольку ключ может не существовать. Таким образом, вы получите Any??.

Нет необходимости объявлять ваш словарь необязательными значениями.

Измените его на [String: Any]?, и ваша проблема исчезнет.

3 голосов
/ 11 июля 2019

Поскольку тип dictionary значение вспомогательного сценария равно Any? со словарем, всегда добавляйте ? к key/value access = Any??

вы можете заменить

[String: Any?]? 

с

[String: Any]? 
1 голос
/ 12 июля 2019

Никто, похоже, на самом деле не объяснял сообщение об ошибке, поэтому я продолжу и сделаю это.

Начиная с простого Int

Предположим, у вас есть целое число i, которое я представлю в виде диаграммы:

let i = 123
// ┏━━━━━━━━━━━━┓
// ┃ Name: i    ┃
// ┃ Type: Int  ┃
// ┠────────────┨
// ┃ Value: 123 ┃
// ┗━━━━━━━━━━━━┛

Any

Вы можете "упаковать" i в значение типа Any. Этот контейнер "скрывает" Int ness 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 "непрозрачен" для системы типов, так как система типов не может определить, что находится за рамкой рамки Any (поэтому я представляю ее сплошным контуром).

Optional<T>

Необязательно - это обобщенное перечисление с двумя падежами: some (в котором хранится ассоциированное значение с именем wrapped) и none (что не так). Он универсален для любого типа T, но для целей этого примера я расскажу только о случае, когда T равен Int, поэтому Optional<Int>, a.k.a. Int?.

nil - сокращение от Optional<T>.none для любого типа 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 ┃  ╏
// ╏  ┗━━━━━━━━━━━━┛  ╏
// ┗╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍┛

В отличие от 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?. Есть 3 возможных результата:

  1. Для ключа существует значение, отличное от nil. Это похоже на константу someSome123 выше
  2. Для ключа существует значение, но значение nil. Это как постоянная someOfNone выше
  3. Не существует значения для ключа. Это как постоянная none выше

Многие языки позволяют всем типам хранить значение null. Это более слабый дизайн, потому что он не может различить № 2 и № 3. «Означает ли это 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.

Чтобы обойти это предупреждение, вы можете выполнить одно из трех его предложений:

  1. укажите значение по умолчанию, чтобы избежать этого предупреждения

    Отогните один слой опциональности, развернув его содержимое или прибегнув к значению по умолчанию, если оно nil. Это редко хорошая идея, потому что разумные значения по умолчанию редко существуют.

    let optionalAny123: Any? = optionalOptionalAny ?? 0
    
  2. принудительно разверните значение, чтобы избежать этого предупреждения

    Отогните один слой опциональности, принудительно развернув его. Это редко хорошая идея, потому что она требует, чтобы вы были абсолютно уверены, что у вас нет nil.

    let optionalAny123: Any? = optionalOptionalAny!
    
  3. явно приведен к 'Any?' с "как-нибудь?" заставить замолчать это предупреждение

    Вы можете оставить значение как есть (с 2 уровнями необязательности), скрыв один из слоев необязательности за вуалью Any.Добавление as Any? на самом деле ничего не делает во время выполнения.Это синтаксическая соль, которая указывает на то, что вы намеренно хотели этого поведения, а не ошибочно позволяли ему ускользнуть.

    let optionalAny123: Any? = optionalOptionalAny as Any?
    

В идеале вы должны попытаться сгладить необязательность, как только сможете.Если вложенность необязательного элемента имеет какое-то значение в вашей системе, действуйте в соответствии с этим как можно скорее, а вскоре после этого сглаживайте необязательное значение.

1 голос
/ 11 июля 2019

Я хочу добавить пример того, что сказал Рмадди.

Предположим, у нас есть следующий код:

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"))

В начале, даже если мы не объявляем какое-либо необязательное значение, словарь не знает, существует ли ключ на самом деле. Таким образом, вы можете лучше понять, почему у вас есть другое необязательное значение, которого вы не ожидали.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...