Подтвердить что ты не робот

Сравнение дополнительных массивов

Выполнение следующего фрагмента кода на игровой площадке дает ошибку:

let a: [Int]? = [1,2]
let b: [Int]? = [1,2]
a == b // value of optional type '[Int]?' not unwrapped; did you mean to use '!' or '?'?

Выполняя что-то подобное для "более простого" необязательного типа, выполните:

var x: Int? = 10
var y: Int?
x == y // false

Какова аргументация по первому случаю, необязательных массивов, не допускается? Почему Swift сначала не видит, есть ли какая-либо сторона, если nil (.None), а затем, если это не так, выполните фактическое сравнение массива.

4b9b3361

Ответ 1

Причина, по которой он работает для более простых типов, заключается в том, что существует версия ==, которая определена для опций, которые содержат типы Equatable:

func ==<T : Equatable>(lhs: T?, rhs: T?) -> Bool

Но пока Int есть Equatable, Array не (потому что он может содержать что-то, что не является равнозначным - в этом случае, как это могло бы быть). Все вещи Equatable имеют оператор ==, но не все вещи с оператором == Equatable.

Вы можете написать специальную версию == специально для необязательных массивов, содержащих равнозначные типы:

func ==<T: Equatable>(lhs: [T]?, rhs: [T]?) -> Bool {
    switch (lhs,rhs) {
    case (.Some(let lhs), .Some(let rhs)):
        return lhs == rhs
    case (.None, .None):
        return true
    default:
        return false
    }
}

Вы также можете обобщить это, чтобы покрыть любую коллекцию, содержащую равнозначные элементы:

func ==<C: CollectionType where C.Generator.Element: Equatable>
  (lhs: C?, rhs: C?) -> Bool {
    switch (lhs,rhs) {
    case (.Some(let lhs), .Some(let rhs)):
        return lhs == rhs
    case (.None, .None):
        return true
    default:
        return false
    }
}

Ответ 2

добавление быстрой версии 3 ответа Airspeed:

func ==<T: Equatable>(lhs: [T]?, rhs: [T]?) -> Bool {
  switch (lhs,rhs) {
  case (.some(let lhs), .some(let rhs)):
    return lhs == rhs
  case (.none, .none):
    return true
  default:
    return false
  }
}

func ==<C: Collection where C.Iterator.Element: Equatable>(lhs: C?, rhs: C?) -> Bool {
  switch (lhs,rhs) {
  case (.some(let lhs), .some(let rhs)):
    return lhs == rhs
  case (.none, .none):
    return true
  default:
    return false
  }
}

Ответ 3

Самый простой способ - не использовать дополнительный массив и использовать пустой массив ([]) вместо nil - в случае, если вам не нужно различать эти два случая.

let a = [1,2]
let b = [1,2]
let c = []
a == b
b != c

Он работал в моем случае, когда я писал Equatable extension для struct. Вместо использования свойства categories: [Category]? я только что изменил его на categories: [Category] и проанализировал отсутствующие категории как пустой массив ([]).