【问题标题】:In Swift, can you create a protocol which requires a particular function only when certain conditions hold about the associated types?在 Swift 中,您能否创建一个协议,该协议仅在关联类型的特定条件成立时才需要特定函数?
【发布时间】:2019-03-24 21:56:12
【问题描述】:

我想表达一个 Swift 协议,类似于以下两个都无法编译的 sn-ps。

尝试 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


    【解决方案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)
        }
    }
    

    【讨论】:

    • 这不是我想要的,但很接近。在我的代码中,我有一个结构FreeVectorSpace<T> 和另一个结构FreeLinearMap<T,S>,它是一个函数(T) -> FreeVectorSpace<S> 的包装器。我想让FreeLinearMap<T,S> 只符合一个协议以涵盖两种用法,但这使我能够使用extension FreeLinearMap: AbstractEndofunction where T == S,这非常接近。
    【解决方案2】:

    我认为你做不到。不过,我可以看到另外两种可能对您有所帮助的方法。

    通过对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
       ...
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-28
      • 1970-01-01
      • 2015-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多