繁体   English   中英

如何为函数的通用Array参数(而不是为其Generator.Element)添加类型约束(协议一致性)

[英]How to add a type constraint (protocol conformance) for a generic Array parameter of a function (and not for its Generator.Element)

问题背景

我有一个问题是基于我自己的尝试来为以下线程的OP所希望的行为提供令人满意的解决方法:

这个主题(就像SO上的其他几个例子一样)试图模仿符合某种协议的通用数组扩展。 此线程中最近有一个与此主题相关的类似问题:


我的问题涵盖了下一步。 可以说,我们设法对Array实现了某种通用的扩展,符合某些协议的蓝图,例如MyProtocol 因此,从现在开始,假设对于某些类型的Generator.Element (例如,对于MyTypes ), Array实例现在已扩展并符合MyProtocol

然后,对于以通用Array (或具体地说,说<U: _ArrayType ...或可能的RangeReplaceableCollectionType ...SequenceType ... )类型作为参数的函数, 有没有办法向其添加类型约束实际的通用数组U ),而不仅仅是其Generator.Element类型? (所以不是... where Generator.Element.Type == SomeTypeConstraint )。

我将尝试展示我的问题“正在执行”,以帮助说明我的实际要求。 请注意,这是我为此能够构造的最大的MWE,如果可能有点大的话,我深表歉意。

协议(协议MyTypes用作型+协议MyProtocol用于阵列扩展名):

/* Used as type constraint for Generator.Element */
protocol MyTypes {
    var intValue: Int { get }
    init(_ value: Int)
    func *(lhs: Self, rhs: Self) -> Self
    func +=(inout lhs: Self, rhs: Self)
}

extension Int : MyTypes { var intValue: Int { return self } }
extension Double : MyTypes { var intValue: Int { return Int(self) } }
/* Let's not extend 'Float' for now
   extension Float : MyTypes { var intValue: Int { return Int(self) } } */

/* Used as extension to Array : blueprints for extension method
   to Array where Generator.Element: are constrainted to MyTypes */
protocol MyProtocol {
    //typealias T
    func foo<T: MyTypes>(a: [T]) -> Int?
}

通过MyProtocol扩展Array ; 蓝图方法的实现:

extension Array : MyProtocol {
    func foo<T: MyTypes>(a: [T]) -> Int? {
        /* [T] is Self? proceed, otherwise return nil */
        if let b = self.first {
            if b is T && self.count == a.count {
                var myMultSum: T = T(0)

                for (i, sElem) in self.enumerate() {
                    myMultSum += (sElem as! T) * a[i]
                }
                return myMultSum.intValue
            }
        }
        return nil
    }
}

在某些测试中,对于一个函数,我们将Array参数的Generator.Element约束为MyTypes ,因此有些隐式地断言只有符合MyProtocol数组才能使用该函数:

/* Tests */
let arr1d : [Double] = [1.0, 2.0, 3.0]
let arr2d : [Double] = [-3.0, -2.0, 1.0]

let arr1f : [Float] = [1.0, 2.0, 3.0]
let arr2f : [Float] = [-3.0, -2.0, 1.0]

func bar1<U: MyTypes> (arr1: [U], _ arr2: [U]) -> Int? {
    return arr1.foo(arr2)
}
let myInt1d = bar1(arr1d, arr2d) // -4, OK

//let myInt1f = bar1(arr1f, arr2f)
    /* Error: Cannot convert value of type '[Float]'
       to expected argument type '[_]'

  OK! Expected as 'Float' does not conform to MyTypes protocol */

现在我们到达了我的问题的核心,我无法构造自己的东西:是否有任何可能的方法来将数组泛型(例如U 显式地约束到MyProtocol (对于某些Generator.Elements ,该Array具有被约束)? 我想做点什么

func bar2<T: MyTypes, U: protocol<MyProtocol, _ArrayType> where U.Generator.Element == T> (arr1: U, _ arr2: U) -> Int? {

    // OK, type 'U' behaves as an array type with elements 'T' (==MyTypes)
    var a = arr1
    var b = arr2
    a.append(T(0))
    b.append(T(0))

    return a.foo(b)
        /* Error: Cannot convert value of type 'U'
           to expected argument type '[_]'          */
}
let myInt2 = bar2(arr1d, arr2d)
  • 这可能是可能的吗?

(可以随意编辑该问题以进行改进,我不太了解此处提出问题的过程以及最佳实践)

我设法通过以下方式解决了“按部就班”的提案工作:

  • <U: SequenceType ...切换到<U: _ArrayType ... (请参见编辑历史记录),

  • 为了用通用数组(generic U )调用我的通用数组扩展,在调用中显式初始化一个数组,显式告知接收者(通用类型U )的调用方参数是Array类型(使用Array(...)初始值设定项) 。

因此,我们可以使用问题中描述的通用数组扩展,为函数的通用数组参数添加类型约束(协议一致性),然后采用以下方法进行协议一致性:

func bar2<T: MyTypes, U: protocol<MyProtocol, _ArrayType> where U.Generator.Element == T> (arr1: U, _ arr2: U) -> Int? {

    // OK, type U behaves as array type with elements T (=MyTypes)
    var a = arr1
    var b = arr2
    a.append(T(2)) // add 2*7 to multsum
    b.append(T(7))

    return a.foo(Array(b))
        /* Ok! */
}
let myInt2 = bar2(arr1d, arr2d) // -4+2*7 = 10, OK

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM