在Swift中,您是否可以创建一个仅在某些条件保持关联类型时才需要特定功能的协议?

问题描述 投票:0回答:2

我想表达一个类似于以下两个片段的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的实例。如果有一个类型Vector2Vector3,可以想象创建类型Matrix2x2Matrix2x3Matrix3x3并使它们符合AbstractFunction协议。 MatrixNxM的领域是VectorM,而codomain将是VectorN。方形矩阵具有单位矩阵,但是当域和密码域不同时,单位矩阵(或真正的身份函数)的概念没有意义。

因此,我希望协议AbstractFunction要求符合类型提供身份,但仅限于Domain == Codomain的情况。这可能吗?

swift swift-protocols associated-types
2个回答
1
投票

您可以通过声明第二个更严格的协议来实现它:

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 { $0 }

    private let function: (Int) -> Int

    init(_ function: @escaping (Int) -> Int) {
        self.function = function
    }

    func apply(_ x: Int) -> Int {
        return function(x)
    }
}

0
投票

我认为你不能这样做。但是,我可以看到另外两种方法可以帮助你。

通过对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
   ...
}
© www.soinside.com 2019 - 2024. All rights reserved.