web-dev-qa-db-fra.com

Générique Swift 4 enum avec Void type associé

tl; dr

Est-il possible d'instancier un membre enum Swift 4 enum avec une valeur associée de type Void?

Contexte

J'utilise une énumération simple Result (similaire à Résultat antitypical ):

enum Result<T> {
  case success(T)
  case error(Error?)
}

Maintenant, je voudrais utiliser cette énumération pour représenter le résultat d'une opération qui ne donne pas de valeur de résultat réelle; l'opération est soit réussi ou échoué. Pour cela, je définirais le type comme Result<Void>, Mais je n'arrive pas à créer l'instance de résultat, ni let res: Result<Void> = .success Ni let res: Result<Void> = .success() ne fonctionne.

30
dr_barto

Dans Swift 3, vous pouvez omettre la valeur associée de type Void:

let res: Result<Void> = .success()

Dans Swift 4 vous devez passer une valeur associée de type Void:

let res: Result<Void> = .success(())
// Or just:
let res = Result.success(())
58
Martin R

Dans Swift 4, un cas d'énumération avec une valeur associée Void n'est plus équivalent à un cas d'énumération avec une liste vide de valeurs associées.

Je crois que c'est, comme Martin dit , un résultat de SE-0029 où vous ne pouvez plus passer un Tuple d'arguments à une fonction et les avoir "splat" à travers le paramètres (bien que la proposition ait été marquée comme implémentée en Swift 3, je crois que ce cas particulier a été repris plus tard dans l'implémentation de SE-011 for Swift 4).

Par conséquent, cela signifie que vous ne pouvez plus appeler un (Void) -> T comme un () -> T in Swift 4. Vous devez maintenant passer Void explicitement:

let result = Result.success(())

Cependant, je trouve cela assez moche, donc j'implémente généralement une extension comme celle-ci:

extension Result where T == Void {
    static var success: Result {
        return .success(())
    }
}

Ce qui vous permet de dire des choses comme ça:

var result = Result.success
result = .success

Il convient de noter que cette solution de contournement ne se limite pas aux cas d'énumération, elle peut également être utilisée avec des méthodes en général. Par exemple:

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()
30
Hamish

Void est une simple typealias pour un Tuple vide: () afin que vous puissiez l'utiliser comme suit:

let res1: Result<Void> = .success(())
let res2 = Result<Void>.success(())
let res3 = Result.success(() as Void)
let res4 = Result.success(())
3
KaQu