假设我想将一些功能公开为公共API,但实现的一部分是指内部协议:
public protocol P {
var foo: Int { get }
}
internal protocol Q {
init(from: [String])
}
public struct S: P, Q {
public var foo: Int = 0
public init() {}
internal init(from: [String]) {
precondition(from.count > 0)
self.foo = Int(from[0])!
}
}
这将是一些数据对象,只有我自己的模块可以构建(来自某些数据表示),但模块的用户可以用于他们自己的目的。
假设我想提供一些服务,它接受这样的值并返回一个相同类型的新服务:
public class ProviderOfThings {
public func map<T: P>(before: T) -> T {
return T(from: [String(before.foo + 1)])
}
}
这不编译; T
上没有合适的初始值设定项。
如何以通用的方式调用我(内部)知道的构造函数?
答案 0 :(得分:1)
我们可以将值转换为内部协议类型并从那里访问初始化程序:
public static func map<T: P>(before: T) -> T {
return type(of: before as! Q).init(
from: [String(before.foo + 1)]
) as! T
}
我们甚至可以没有类型的值(谢谢,Hamish!):
public static func make<T: P>() -> T {
return (T.self as! Q.Type).init(
from: ["0"]
) as! T
}
如果P
的某些(或可能)实现不符合Q
,则需要谨慎转换为Q
:
guard let beforeQ = before as? Q else { ... }
// or
guard before is Q else { ... }
// respectively
guard T.self is Q.Type else { ... }
另一个演员as! T
是安全的:毕竟我们称之为T
的初始值设定项。因此,如果保护,此解决方案不会导致运行时错误。
使用示例here查找完整代码。
答案 1 :(得分:0)
我认为最好的方法是将map
声明如下:
public func map<T: P & Q>(before: T) -> T
并公开Q
,如果外部代码不应该使用_
,则可以在其前面添加{。}}。