簡體   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