Generic Swift 4 enum с ассоциированным с Void типом
TL;DR
Возможно ли создать экземпляр элемента перечисления Swift 4 с ассоциированным значением типа Void
?
Фон
Я использую простое перечисление результатов (похожее на antitypical Result):
enum Result<T> {
case success(T)
case error(Error?)
}
Теперь я хотел бы использовать это перечисление для представления результата операции, которая не дает фактического значения результата; операция либо преуспела, либо не удалась. Для этого я бы определил тип как Result<Void>
, но я борюсь с тем, как создать экземпляр Result, ни let res: Result<Void> = .success
, ни let res: Result<Void> = .success()
не работает.
Ответы
Ответ 1
В Swift 3 вы можете опустить связанное значение типа Void
:
let res: Result<Void> = .success()
В Swift 4 вам необходимо передать связанное значение типа Void
:
let res: Result<Void> = .success(())
// Or just:
let res = Result.success(())
Ответ 2
В Swift 4 событие enum со связанным значением Void
больше не эквивалентно случаю enum с пустым списком связанных значений.
Я считаю, что это как говорит Мартин, результат SE-0029, где вы больше не можете передавать кортеж аргументов функции и иметь "splat" по всем параметрам (хотя предложение было отмечено в Swift 3, я считаю, что этот конкретный случай был взят позже в реализации SE-0110 для Swift 4).
В результате это означает, что вы больше не можете называть (Void) -> T
как () -> T
в Swift 4. Теперь вам нужно передать Void
в явном виде:
let result = Result.success(())
Однако я нахожу это довольно уродливым, поэтому я обычно реализую расширение следующим образом:
extension Result where T == Void {
static var success: Result {
return .success(())
}
}
Что позволяет говорить такие вещи:
var result = Result.success
result = .success
Стоит отметить, что это обходное решение не ограничивается только перечисляемыми случаями, оно также может использоваться с методами в целом. Например:
struct Foo<T> {
func bar(_ a: T) {}
}
extension Foo where T == Void {
func bar() { bar(()) }
}
let f = Foo<Void>()
// without extension:
f.bar(())
// with extension:
f.bar()
Ответ 3
Void - это простые типы для пустого кортежа:(), поэтому вы можете использовать его как любое из следующих:
let res1: Result<Void> = .success(())
let res2 = Result<Void>.success(())
let res3 = Result.success(() as Void)
let res4 = Result.success(())