Swift 问题:如果非可选变量是协议类型,我们如何在 if else 块中初始化它?

Swift question: how can we init an non-optional variable in a if else block if it's of protocol type?

在Swift中,我们可以不立即初始化非可选变量,而是稍后在 if else 块中初始化,例如:

let result: Bool
if something {
   result = computeSomething()
} else {
   result = computeSomethingElse()
}

但是如果我的变量是协议类型呢? (在我的示例中,我想使用作为协议的 GraphQLMutation 来执行此操作):

let mutation: GraphQLMutation
if something {
   mutation = StartMutation()
} else {
   mutation = StopMutation()
}
self.graphQLDataSource.set(mutation: mutation)

Swift 编译器错误说: Protocol 'GraphQLMutation' can only be used as a generic constraint because it has Self or associated type requirements

有没有办法做到这一点并避免代码重复?

它确实适用于协议:

protocol Foo {}
struct A: Foo {}
class B: Foo {}

let x: Foo
if Bool.random() {
    x = A()
} else {
    x = B()
}

它只是不适用于具有关联类型的协议。您只能在通用函数中使用它。这是一些展示它的代码:

protocol Foo {
    associatedtype T
}
struct A: Foo {
    typealias T = Int
}
class B: Foo {
    typealias T = String
}

func x<Foo>(_ test: Bool) -> Foo? {
    let x: Foo?
    if test {
        x = A() as? Foo
    } else {
        x = B() as? Foo
    }
    return x
}

let a1: A? = x(true)  // => A
let a2: A? = x(false) // => nil

let b1: B? = x(true)  // => nil
let b2: B? = x(false) // => B
  • 对于 a1 我们得到了一个 A 的实例,因为转换 A() as? Foo 有效,因为它有一个 Foo 类型和关联类型Intlet a1: A?.

  • 要求
  • 对于 a2 我们得到 nil,因为转换 B() as? Foo 失败,因为它不能被转换为 Foo 与所需的关联类型 Int let a2: A?.

  • 对于 b1 我们得到 nil,因为转换 A() as? Foo 失败,因为它不能被转换为 Foo 与所需的关联类型 String let b1: B?.

  • 对于 b2 我们得到了一个 B 的实例,因为转换 B() as? Foo 有效,因为它有一个 Foo 类型和关联类型Stringlet b2: B?.

  • 要求