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

标签 arrays swift generics

问题背景

我有一个问题是基于我自己尝试为以下线程的 OP 想要的行为产生令人满意的解决方法:

主题是(像 SO 的其他一些人一样...)试图模仿符合某些协议(protocol)的通用数组扩展。最近在这个线程中有一个关于这个主题的类似问题:


问题

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

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

例子

我将尝试“实际”展示我的问题,以帮助说明我实际要问的内容。请注意,这是我为此目的能够构建的最大 MWE,如果它可能有点重,我深表歉意。

协议(protocol)(协议(protocol) MyTypes 用作类型 + 协议(protocol) 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?
}

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

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
    }
}

一些测试,我们对于一个函数,约束 Generator.ElementArray 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 (对于哪些 Array 对于某些 Generator.Elements 已被约束)?我想做一些事情

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)
  • 这可能吗,或许以不同的方式?

(随意编辑这个问题以改进它,我不是很精通在 SO 上提问的过程和最佳实践)

最佳答案

我设法修复了我的“做一些事情”提案工作,方法是:

  • <U: SequenceType ... 切换到 <U: _ArrayType ...(查看编辑历史记录),

  • 为了使用泛型数组(泛型 U)调用我的泛型数组扩展,在调用中显式初始化一个数组,显式告诉接收方调用者参数(泛型 U)的类型为 Array(使用 Array(...) 初始化器) ).

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

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

关于arrays - 如何为函数的通用数组参数(而不是其 Generator.Element)添加类型约束(协议(protocol)一致性),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34501723/

相关文章:

Java 泛型 : override method that differs in parameterized return type

PHP多数组回显

ios - 插入一个数组会影响另一个数组吗?

javascript - 求嵌套数组内值的总和

Java 泛型和 addAll 方法

r - 在 R 中,如何从另一个包中的一个包扩展泛型方法?

php - 我的循环创建另一个父数组而不是将其附加到我指向的位置?

ios - 在 Swift 的属性声明期间引用 self

ios - Swift 2.2 – 如何为 UIView 中嵌套的 UIButton 调用 TouchesShouldCancelInContentView?

ios - 在 iPad 屏幕上按下 Controller 两次