Swift enum соответствует идентифицируемому: тип не соответствует идентифицируемому протоколу
У меня есть перечисление со связанными значениями, которые я хочу использовать в качестве элемента в RxDataSources. Я попытался привести его в соответствие с идентифицируемым, сопоставив его с Hashable, как показано ниже.
enum DriverHubWidget: Hashable, Identifiable {
static func == (lhs: DriverHubWidget, rhs: DriverHubWidget) -> Bool {
return lhs.hashValue == rhs.hashValue
}
var id: Int { hashValue }
case greetings(DriverHubGreetingsViewModel)
case scorecard(DriverHubScorecardSummary?, Error?)
case optOut
func hash(into hasher: inout Hasher) {
switch self {
case .greetings( _):
return hasher.combine(1)
case .scorecard( _, _):
return hasher.combine(2)
case .optOut:
return hasher.combine(3)
}
}
}
Я реализовал хэш-функцию, просто присвоив каждому случаю значение Int. Затем, чтобы соответствовать идентифицируемому, я добавил свойство id, которое возвращает hashValue. Это компилируется просто отлично.
Теперь, когда я пытаюсь использовать это, чтобы объявить псевдоним типа для модели раздела, как показано ниже
typealias WidgetSection = AnimatableSectionModel<String, DriverHubWidget>
Он компилируется и выдает ошибку,
Type 'DriverHubWidget' does not conform to protocol 'IdentifiableType'
Я не могу понять, почему он не работает, он отлично компилируется, когда перечисление соответствует Hashable и Identifying, но при использовании соответствие каким-то образом недействительно. Это потому, что связанные значения для перечислений не Hashable?
2 ответа
Вы спуталиIdentifiable
, встроенный протокол Swift, с, протокол в библиотеке RxDataSource.
Вы можете просто соответствовать
IdentifiableType
.
enum DriverHubWidget: Hashable, IdentifiableType {
var identity: Int {
hashValue
}
...
}
Хотя то, как ты подчиняешься, кажется мне странным. Вы считаете два значения перечисления равными, если они относятся к одному и тому же регистру, и игнорируете связанные с ними значения. То есть,
.greeting(x) == .greeting(y)
было бы правдой. Это кажется довольно нелогичным. Если это действительно то, что вам нужно, вы можете просто реализовать
identity
Сюда:
var identity: Int {
switch self {
case .greetings( _):
return 1
case .scorecard( _, _):
return 2
case .optOut:
return 3
}
}
и соответствовать, фактически принимая во внимание связанные ценности, или не соответствовать
Hashable
вообще.
(Это не полный ответ, но он слишком длинный для комментария. Считайте это дополнением к тому, что уже сказал Sweeper)
Чтобы объекты были , они должны иметь стабильное (т.е. не меняющееся во времени) понятие идентичности, которое отличает их от других родственных объектов. Какое именно понятие идентичности имеет смысл для ваших целей, зависит от вас. Как упоминается в документации :
Идентифицируемый оставляет продолжительность и область действия удостоверения неопределенными.
- Удостоверения могут иметь любую из следующих характеристик: Гарантируется, что они всегда уникальны, как UUID.
- Постоянно уникальные для каждой среды, такие как ключи записей базы данных.
- Уникальный для всего жизненного цикла процесса, например глобальные увеличивающиеся целые числа.
- Уникальный на протяжении всего времени существования объекта, как и идентификаторы объектов.
- Уникальный в текущей коллекции, например индексы коллекции. И конформер, и получатель протокола должны документировать характер идентичности.
Вы, вероятно, не хотите игнорировать связанные значения из вашего представления об идентичности. В противном случае ваш код может рассматривать два объекта как идентичные, даже если их связанные значения различаются.
На практике это означает, что
DriverHubGreetingsViewModel
,DriverHubScorecardSummary
также необходимо будет соответствоватьIdentifiable
. ВашError?
связанное значение, которое вы, вероятно, захотите превратить в(Error & Identifiable)?
*Вы не можете деликатно реализовать
id
кhashValue
, потому что хэш-значения (по замыслу) непредсказуемы. Вполне возможно, что все три ваших случая окажутся с одним и тем же идентификатором (это произошло бы, если бы хэш был засеян таким образом, что все хэши 1, 2 и 3 столкнулись)
Еще одно замечание: необязательная модель, за которой следует необязательная ошибка, — это запах кода в Swift. Это наследие Objective C, в системе типов которого отсутствовал упрощенный способ выражения значения того или иного типа (тип «или» или «сумма»). Swift поддерживает перечисления со связанными значениями (вы уже используете одно из них!), которые могут быть даже общими. Один из них уже встроен в стандартную библиотеку:Result<Success, Failure>
Так что вместо
case scorecard(DriverHubScorecardSummary?, Error?)
, Я бы порекомендовал:
case scorecard(Result<DriverHubScorecardSummary, Error & Identifiable>)