【问题标题】:Generic Swift 4 enum with Void associated type具有 Void 关联类型的通用 Swift 4 枚举
【发布时间】:2018-01-31 22:29:34
【问题描述】:

tl;dr

是否可以使用Void 类型的关联值来实例化通用 Swift 4 枚举成员?

背景

我正在使用一个简单的 Result 枚举(类似于antitypical Result):

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

现在我想用这个枚举来表示一个不会产生实际结果值的操作的结果;操作要么成功,要么失败。为此,我将类型定义为 Result&lt;Void&gt;,但我正在努力创建 Result 实例,let res: Result&lt;Void&gt; = .successlet res: Result&lt;Void&gt; = .success() 都不起作用。

【问题讨论】:

  • 你确定第二种方式吗?看起来它可以工作swift.sandbox.bluemix.net/#/repl/599d61b1b459cc41aee76d9d
  • 有趣,谢谢你的例子。我重新检查了,但在 Xcode 9 Beta 5 中我得到了Missing argument for parameter #1 in call
  • @Hamish:你可能是对的(我还在 SE-0110 和 SE-0029 ... :)
  • @Hamish:这也可能是 SE-0029 的结果:“构造函数”let f = Result&lt;Void&gt;.success 在 Swift 3 和 4b5 中都具有 (Void) -&gt; Result&lt;Void&gt; 类型。在 Swift 3 中你可以调用 let r = f(),在 4b5 中你必须添加一个参数:let r = f(())

标签: swift enums swift4


【解决方案1】:

在 Swift 3 中,您可以省略 Void 类型的关联值:

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

在 Swift 4 中,您必须传递 Void 类型的关联值:

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

【讨论】:

  • 有不那么丑陋的解决方案吗?
  • @RodrigoRuiz 你可以定义一个扩展来摆脱(())see my answer
【解决方案2】:

在 Swift 4 中,具有 Void 关联值的枚举案例不再等同于具有空关联值列表的枚举案例。

我相信这是,as Martin saysSE-0029 的结果,您不能再将参数元组传递给函数并让它们在参数中“splat”(尽管该提案被标记为在 Swift 3 中实现) ,我相信这个特殊情况后来在 Swift 4 的 SE-0110 的实现中得到了体现。

因此,这意味着您不能再在 Swift 4 中将 (Void) -&gt; T 称为 () -&gt; T。您现在必须明确传递 Void

let result = Result.success(())

但是,我觉得这很丑,所以我通常实现这样的扩展:

extension Result where Success == 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()

【讨论】:

  • ((很好))。没有意识到您可以根据泛型类型定义变量。
  • 很棒的解决方案!我从 .success(Void()) 移到了这里
  • Swift 5 版本将是 extension Result where Success == Void { ... },但由于某种原因,let r1 = Result&lt;Void, Error&gt;.success 无法通过“Ambiguous use of 'success'”编译,但 let r2: Result&lt;Void, Error&gt; = .success 编译没有问题。
  • @MartinR 这很糟糕——问题是Result&lt;Void, Error&gt;.success 可以同时引用.success 的枚举案例构造函数或静态变量。已经有一个排名规则更喜欢 vars 而不是函数,但是目前不考虑枚举案例构造函数:(。let r2: Result&lt;Void, Error&gt; = .success 有效,因为只有静态 var 的类型为 Result&lt;Void, Error&gt;Result.success 的原因在我的原始示例是因为没有指定通用占位符,所以只能解析为静态变量,因为它满足占位符Void
  • 不幸的是,除了let r2: Result&lt;Void, Error&gt; = .success 之外,我认为目前没有很好的解决方法。理想情况下,重载排名规则将更改为将枚举案例构造函数更像静态函数。更好的是,如果枚举案例构造函数在 AST 中被表示为隐式生成的静态函数,这将有助于消除与它们的其他不一致(尽管这可能不可能在 ABI 后稳定,因为我不确定重整将是相同的)。
【解决方案3】:

Void 是空元组的简单类型别名:(),因此您可以将其用作以下任何一种:

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

【讨论】:

    【解决方案4】:

    Swift 5 已将 Result 更新为需要 Failure 参数,但仍需要关联值:

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

    【讨论】:

      【解决方案5】:

      我发现.success(Void()) 更具描述性和简单性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-23
        • 1970-01-01
        • 2021-11-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多