Swift 5,在XCode 11.2.1上。我已经永远用Java编程了,在这一点上我只是对Swift有所了解,所以我的一些理解被Java习惯用语所染。
假设我们提供了一个协议,或者可能是一个伪抽象类,可以在一个单独的模块中实现。然后,程序员将对类的引用传递回第一个模块中的代码,从而实例化其类。现在,在Java中这很困难,因为您无法保证子类将定义哪些初始化器/静态方法。但是,在Swift中,您可以。这很整洁。除了,我还没有找到使用它们的方法。我expect的意思是您可能拥有类似的代码,例如
protocol FooP {
init(s: String)
}
func instantiate(clazz: FooP.Type) -> FooP {
return clazz.init(s: "qwerty")
}
... OOOOORRRR确实可以正常工作,正如我希望的那样。我认为在测试中,我只是未能找到CLASS / .Type / .self的正确组合来提示我成功的可能性。
由于搜寻了30-60分钟,尽管我没有找到关于此可能性的任何其他信息,我会回答我自己的问题。
事实证明,即使所涉及的类(而不是其实例化)被强制转换为其协议,也可以使用协议提供的静态方法。您甚至可以使用泛型来使示例instantiate
方法更方便地具有您提供的返回类型,尽管这会导致如下所示的其他问题。这是一堆代码,展示了您可以做和不能做的事情:
public protocol ProtocolTest {
init(s: String)
static func factory(s: String) -> Self
}
public class Foo : ProtocolTest, CustomStringConvertible {
public let s: String
public required init(s: String) {
self.s = s
}
public static func factory(s: String) -> Self {
return Self(s: s)
}
public var description: String { return "{\(Self.self)|s:\"\(s)\"}" }
}
public class Bar : Foo {
}
public func instantiateGeneric<T : ProtocolTest>(clazz: T.Type) -> T {
return clazz.init(s: "qwertyGeneric")
}
public func instantiateNongeneric(clazz: ProtocolTest.Type) -> ProtocolTest {
return clazz.init(s: "qwertyNongeneric")
}
public func run() {
let ptts: [ProtocolTest.Type] = [Foo.self, Bar.self]
// Success
let aInit : Bar = Bar.init(s: "qwertyInit")
// Success
let aGeneric : Bar = instantiateGeneric(clazz: Bar.self)
// Compile error: Cannot convert value of type 'ProtocolTest' to specified type 'Bar'
let aNongeneric : Bar = instantiateNongeneric(clazz: Bar.self)
for ptt in ptts {
// Success
let bInit : ProtocolTest = ptt.init(s: "qwertyInit")
// Compile error: Protocol type 'ProtocolTest' cannot conform to 'ProtocolTest' because only concrete types can conform to protocols
let bGeneric1 : ProtocolTest = instantiateGeneric(clazz: ptt)
// Compile error: Cannot invoke 'instantiateGeneric' with an argument list of type '(clazz: ProtocolTest.Type)'
let bGeneric2 = instantiateGeneric(clazz: ptt)
// Success
let bNongeneric : ProtocolTest = instantiateNongeneric(clazz: ptt)
// This works too, btw:
let bFactory : ProtocolTest = ptt.factory(s: "qwertyFactory")
}
}
我不确定循环中instantiateGeneric
到底发生了什么。似乎是合理的代码行。让我知道您是否有解释。也许关于<T : ProtocolTest>
,ProtocolTest
在技术上不符合ProtocolTest
,或者也许它必须是严格的子类?不确定。能够在两种用途中使用相同的方法会很好,但是我已经对自己可以做的事情感到非常满意。这个发现可能足以让我真正喜欢Swift,哈哈。