[英]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.