在 Swift 中,您能否创建一个仅在特定条件满足关联类型时才需要特定功能的协议?
In Swift, can you create a protocol which requires a particular function only when certain conditions hold about the associated types?
我想表达一个 Swift 协议,类似于以下两个都无法编译的片段。
尝试 1:
protocol AbstractFunction {
associatedtype Domain
associatedtype Codomain
func apply(_ x: Domain) -> Codomain
static var identity: Self where Domain == Codomain { get }
}
尝试 2:
protocol AbstractFunction {
associatedtype Domain
associatedtype Codomain
func apply(_ x: Domain) -> Codomain
static func identity() -> Self where Domain == Codomain { get }
}
第一个在 Swift 语法中甚至无效,而第二个失败
'where' clause cannot be attached to a non-generic declaration
.
这两个示例都试图表达一个协议,该协议描述的函数不是实际函数类型的实例 (A) -> B
。如果有类型 Vector2
和 Vector3
,可以想象创建类型 Matrix2x2
、Matrix2x3
和 Matrix3x3
并使它们符合 AbstractFunction
协议. MatrixNxM
的域名为 VectorM
,密码域为 VectorN
。方矩阵有一个单位矩阵,但当域和辅域不同时,单位矩阵(或真正的单位函数)的概念就没有意义了。
因此,我希望协议 AbstractFunction
要求符合类型来提供身份,但仅在 Domain == Codomain
的情况下。这可能吗?
我认为你做不到。但是,我可以看到另外两种可能对您有所帮助的方法。
通过对 identity
使用可选类型,您表示实现 AbstractFunction
的特定类型可能有也可能没有身份。例如:
final class ConcreteFunctionWithoutIdentity: AbstractFunction {
typealias Domain = Int
typealias Codomain = Int
func apply(_ x: Int) -> Int {
return 0
}
static var identity: ConcreteFunctionWithoutIdentity?
}
// Using
if let identity = ConcreteFunctionWithoutIdentity.identity else {
// It will not fall here, since ConcreteFunctionWithoutIdentity doesn't have identity
...
}
final class ConcreteFunctionWithIdentity: AbstractFunction {
typealias Domain = Int
typealias Codomain = Int
func apply(_ x: Int) -> Int {
return 0
}
static var identity: ConcreteFunctionWithtIdentity? {
// return something
}
}
if let identity = ConcreteFunctionWithtIdentity.identity else {
// It will fall here, since ConcreteFunctionWithIdentity indeed have identity
...
}
您可以通过声明第二个更严格的协议来实现它:
protocol AbstractFunction {
associatedtype Domain
associatedtype Codomain
func apply(_ x: Domain) -> Codomain
}
protocol AbstractEndofunction: AbstractFunction where Codomain == Domain {
static var identity: Self { get }
}
关于 Int -> Int 函数的示例:
final class IntFunction: AbstractEndofunction {
typealias Domain = Int
static var identity = IntFunction { [=11=] }
private let function: (Int) -> Int
init(_ function: @escaping (Int) -> Int) {
self.function = function
}
func apply(_ x: Int) -> Int {
return function(x)
}
}
我想表达一个 Swift 协议,类似于以下两个都无法编译的片段。
尝试 1:
protocol AbstractFunction {
associatedtype Domain
associatedtype Codomain
func apply(_ x: Domain) -> Codomain
static var identity: Self where Domain == Codomain { get }
}
尝试 2:
protocol AbstractFunction {
associatedtype Domain
associatedtype Codomain
func apply(_ x: Domain) -> Codomain
static func identity() -> Self where Domain == Codomain { get }
}
第一个在 Swift 语法中甚至无效,而第二个失败
'where' clause cannot be attached to a non-generic declaration
.
这两个示例都试图表达一个协议,该协议描述的函数不是实际函数类型的实例 (A) -> B
。如果有类型 Vector2
和 Vector3
,可以想象创建类型 Matrix2x2
、Matrix2x3
和 Matrix3x3
并使它们符合 AbstractFunction
协议. MatrixNxM
的域名为 VectorM
,密码域为 VectorN
。方矩阵有一个单位矩阵,但当域和辅域不同时,单位矩阵(或真正的单位函数)的概念就没有意义了。
因此,我希望协议 AbstractFunction
要求符合类型来提供身份,但仅在 Domain == Codomain
的情况下。这可能吗?
我认为你做不到。但是,我可以看到另外两种可能对您有所帮助的方法。
通过对 identity
使用可选类型,您表示实现 AbstractFunction
的特定类型可能有也可能没有身份。例如:
final class ConcreteFunctionWithoutIdentity: AbstractFunction {
typealias Domain = Int
typealias Codomain = Int
func apply(_ x: Int) -> Int {
return 0
}
static var identity: ConcreteFunctionWithoutIdentity?
}
// Using
if let identity = ConcreteFunctionWithoutIdentity.identity else {
// It will not fall here, since ConcreteFunctionWithoutIdentity doesn't have identity
...
}
final class ConcreteFunctionWithIdentity: AbstractFunction {
typealias Domain = Int
typealias Codomain = Int
func apply(_ x: Int) -> Int {
return 0
}
static var identity: ConcreteFunctionWithtIdentity? {
// return something
}
}
if let identity = ConcreteFunctionWithtIdentity.identity else {
// It will fall here, since ConcreteFunctionWithIdentity indeed have identity
...
}
您可以通过声明第二个更严格的协议来实现它:
protocol AbstractFunction {
associatedtype Domain
associatedtype Codomain
func apply(_ x: Domain) -> Codomain
}
protocol AbstractEndofunction: AbstractFunction where Codomain == Domain {
static var identity: Self { get }
}
关于 Int -> Int 函数的示例:
final class IntFunction: AbstractEndofunction {
typealias Domain = Int
static var identity = IntFunction { [=11=] }
private let function: (Int) -> Int
init(_ function: @escaping (Int) -> Int) {
self.function = function
}
func apply(_ x: Int) -> Int {
return function(x)
}
}