首页 > 解决方案 > Swift 问题:如果 if else 块是协议类型,我们如何初始化一个非可选变量?

问题描述

在 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

任何想法能够做到这一点并避免代码重复?

标签: swiftvariablesgraphqlprotocolsinit

解决方案


它确实适用于协议:

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我们得到了一个 as 的实例,A因为A() as? Foo它的类型为,Foo并且具有.Intlet a1: A?

  • 因为a2我们在强制转换失败时得到 nil,B() as? Foo因为它不能被强制转换Foo为.Intlet a2: A?

  • 因为b1我们在强制转换失败时得到 nil,A() as? Foo因为它不能被强制转换Foo为.Stringlet b1: B?

  • 因为b2我们得到了一个 as 的实例,B因为B() as? Foo它的类型为,Foo并且具有.Stringlet b2: B?


推荐阅读