Я хочу проверить равенство двух значений перечисления Swift. Например:
enum SimpleToken {
case Name(String)
case Number(Int)
}
let t1 = SimpleToken.Number(123)
let t2 = SimpleToken.Number(123)
XCTAssert(t1 == t2)
Однако компилятор не скомпилирует выражение равенства:
error: could not find an overload for '==' that accepts the supplied arguments
XCTAssert(t1 == t2)
^~~~~~~~~~~~~~~~~~~
Должен ли я определить собственную перегрузку оператора равенства? Я надеялся, что компилятор Swift справится с этим автоматически, так же, как это делают Scala и Ocaml.
Equatable
иHashable
для перечислений со связанными значениями.Ответы:
Swift 4.1+
Как подсказал @jedwidz , из Swift 4.1 (благодаря SE-0185 Swift также поддерживает синтез
Equatable
иHashable
для перечислений со связанными значениями.Так что, если вы используете Swift 4.1 или новее, следующие программы автоматически синтезируют необходимые методы, которые
XCTAssert(t1 == t2)
работают. Ключ должен добавитьEquatable
протокол к вашему перечислению.До Swift 4.1
Как уже отмечалось, Swift не синтезирует необходимые операторы равенства автоматически. Позвольте мне предложить более чистую (IMHO) реализацию, хотя:
Это далеко от идеала - много повторений - но, по крайней мере, вам не нужно делать вложенные переключатели с операторами if внутри.
источник
default
наcase (.Name, _): return false; case(.Number, _): return false
.case (.Name(let a), .Name(let b)) : return a == b
и т.д.false
? Это может быть тривиально, но такого рода вещи могут складываться в определенных системах.enum
и==
функция, и функция должны быть реализованы в глобальной области видимости (за пределами области действия вашего контроллера представления).Реализация
Equatable
является излишним ИМХО. Представьте, что у вас сложное и большое перечисление со многими падежами и множеством разных параметров. Эти параметры также должны бытьEquatable
реализованы. Кроме того, кто сказал, что вы сравниваете случаи перечисления на основе «все или ничего»? Как насчет того, если вы проверяете значение и задали только один конкретный параметр enum? Я настоятельно рекомендую простой подход, например:... или в случае оценки параметров:
Найти более подробное описание здесь: https://mdcdeveloper.wordpress.com/2016/12/16/unit-testing-swift-enums/
источник
if case
иguard case
это просто языковые конструкции, вы можете использовать их где угодно при тестировании равенства перечислений в этом случае, а не только в модульных тестах.Кажется, нет никакого сгенерированного компилятором оператора равенства ни для перечислений, ни для структур.
Чтобы реализовать сравнение на равенство, нужно написать что-то вроде:
[1] См. «Операторы эквивалентности» по адресу https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_43
источник
источник
case (.Simple(let v0), .Simple(let v1))
Также оператор может бытьstatic
внутри перечисления. Смотрите мой ответ здесь.Вот еще один вариант. Он в основном такой же, как и другие, за исключением того, что он избегает вложенных операторов switch с использованием
if case
синтаксиса. Я думаю, что это делает его немного более читабельным (/ bearable) и имеет преимущество, заключающееся в том, что он полностью избегает регистров по умолчанию.источник
Я использую этот простой обходной путь в коде модульного теста:
Для сравнения используется интерполяция строк. Я не рекомендовал бы это для производственного кода, но это сжато и делает работу для модульного тестирования.
источник
"\(lhs)" == "\(rhs)"
.String(describing:...)
или эквивалент"\(...)"
. Но это не работает, если связанные значения отличаются :(Другой вариант - сравнить строковые представления случаев:
Например:
источник
Другой подход с использованием
if case
запятых, который работает в Swift 3:Вот как я написал в своем проекте. Но я не могу вспомнить, откуда у меня появилась идея. (Я гуглил только сейчас, но не видел такого использования.) Любой комментарий будет оценен.
источник
t1 и t2 не являются числами, они являются экземплярами SimpleTokens со связанными значениями.
Ты можешь сказать
Вы можете сказать
без ошибки компилятора.
Чтобы получить значение из t1, используйте оператор switch:
источник
«преимущество» по сравнению с принятым ответом состоит в том, что в операторе переключателя «main» нет регистра по умолчанию, поэтому, если вы добавите enum в другие регистры, компилятор заставит вас обновить остальную часть кода.
источник
Более подробно об ответе mbpro, вот как я использовал этот подход для проверки на равенство быстрых перечислений со связанными значениями с некоторыми крайними случаями.
Конечно, вы можете сделать оператор switch, но иногда приятно просто проверить одно значение в одной строке. Вы можете сделать это так:
Если вы хотите сравнить 2 условия в одном и том же предложении if, вам нужно использовать запятую вместо
&&
оператора:источник
В Swift 4.1 просто добавьте
Equatable
протокол к вашему enum и используйтеXCTAssert
илиXCTAssertEqual
:источник
Вы можете сравнить, используя переключатель
источник