通过符合 Swift 2 中的协议扩展类型化数组
Extending typed array by conforming to a protocol in Swift 2
我想扩展类型化数组 Array<SomeType>
以使其符合协议 SomeProtocol
。现在我知道您可以像下面这样扩展类型化数组:
extension Array where Element: SomeType { ... }
您还可以扩展对象以符合如下协议:
extension Array: SomeProtocol { ... }
但我无法弄清楚让类型化数组符合协议的正确语法是什么,例如:
extension (Array where Element: SomeType): SomeProtocol { ... }
有 Swift 2 位专家知道如何做到这一点吗?
您不能将大量逻辑应用于一致性。它要么符合,要么不符合。但是,您可以对扩展应用一些逻辑。下面的代码可以很容易地设置一致性的具体实现。哪个才是重点。
稍后用作类型约束。
class SomeType { }
这是你的协议
protocol SomeProtocol {
func foo()
}
这是协议的扩展。 foo()
在 SomeProtocol
扩展中的实现创建了一个默认值。
extension SomeProtocol {
func foo() {
print("general")
}
}
现在 Array
使用 foo()
的默认实现符合 SomeProtocol
。所有数组现在都有 foo()
作为方法,这不是很优雅。但它什么也没做,所以它不会伤害任何人。
extension Array : SomeProtocol {}
现在很酷的东西:
如果我们为 Array
创建一个带有 Element
类型约束的扩展,我们可以覆盖 foo()
的默认实现
extension Array where Element : SomeType {
func foo() {
print("specific")
}
}
测试:
let arrayOfInt = [1,2,3]
arrayOfInt.foo() // prints "general"
let arrayOfSome = [SomeType()]
arrayOfSome.foo() // prints "specific"
我自己一直在摆弄一些东西,有一些方法可以在某种程度上模仿您正在寻找的行为。
方法 #1
定义一个协议 SomeType
作为您希望 SomeProtocol
的 Array<SomeType>
扩展涵盖的类型的类型约束;其中后者包含一些您希望扩展的简洁方法的蓝图 Array
.
protocol SomeType {
var intValue: Int { get }
init(_ value: Int)
func *(lhs: Self, rhs: Self) -> Self
func +=(inout lhs: Self, rhs: Self)
}
extension Int : SomeType { var intValue: Int { return self } }
extension Double : SomeType { var intValue: Int { return Int(self) } }
/* Let's not extend 'Float' for now
extension Float : MyTypes { var intValue: Int { return Int(self) } } */
protocol SomeProtocol {
func foo<T: SomeType>(a: [T]) -> Int?
}
现在,您可以将 Array
扩展到 SomeProtocol
,并且通过使用 is
关键字,您可以断言您的泛型 T
(受 SomeType
) 和 Self
的元素通过使用 is
关键字属于同一类型,如果为真,则后跟显式转换:
extension Array : SomeProtocol {
func foo<T: SomeType>(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
}
}
我们现在用 SomeType
的元素扩展了 Array
,并在协议 SomeProtocol
中绘制了函数 foo(...)
。
/* 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 bar<U: SomeType> (arr1: [U], _ arr2: [U]) -> Int? {
return arr1.foo(arr2)
}
let myInt1d = bar(arr1d, arr2d) // -4, OK
let myInt1f = bar(arr1f, arr2f)
/* Compile time error: "Cannot convert value of type '[Float]'
to expected argument type '[_]'" */
好的!我们预计这里会出现最终编译时错误,因为 'Float' 不符合 SomeType
协议。
方法 #2
现在介绍另一种方法:我基于 this excellent post by Milen Dzhumerov 之后的泛型,此处针对数组进行了调整,并使用了一些不同的扩展方法示例。
对于这个例子,我们正在为 Array
:s 类型 Double
或 Float
实现一个 "generic" 协议扩展,由类型约束协议 SomeType
protocol SomeType {
init(_ value: Int)
init(_ value: Double)
init(_ value: Float)
func == (lhs: Self, rhs: Self) -> Bool
}
extension Double: SomeType {}
extension Float: SomeType {}
protocol GenericProtocol {
typealias AbstractType : SequenceType
func repeatNumberNumberManyTimes(arg: Int) -> AbstractType
func removeRandomElement(arg: AbstractType) -> AbstractType
func countNumberOf42s(arg: AbstractType) -> Int
}
使用结构将GenericProtocol
转发给AbstractType
(这里符合SequenceType
),并在后者中实现协议蓝图:
struct SomeArrayProtocol<T: SequenceType> : GenericProtocol {
private let _repeatNumberNumberManyTimes : (Int) -> T
private let _removeRandomElement : (T) -> T
private let _countNumberOf42s : (T) -> Int
init<P : GenericProtocol where P.AbstractType == T>(_ dep : P) {
_repeatNumberNumberManyTimes = dep.repeatNumberNumberManyTimes
_removeRandomElement = dep.removeRandomElement
_countNumberOf42s = dep.countNumberOf42s
}
func repeatNumberNumberManyTimes(arg: Int) -> T {
return _repeatNumberNumberManyTimes(arg)
}
func removeRandomElement(arg: T) -> T {
return _removeRandomElement(arg)
}
func countNumberOf42s(arg: T) -> Int {
return _countNumberOf42s(arg)
}
}
在另一个结构中实现 GenericProtocol
蓝图的实际方法,其中泛型现在被限制为 SomeType
类型约束(协议)。请注意,这是模仿您希望的冷杉(但直接无法实现)形式的部分 extension (Array where Element: SomeType): SomeProtocol { ... }
:
struct SomeArrayGenericExtensions<T: SomeType> : GenericProtocol {
typealias AbstractType = Array<T>
func repeatNumberNumberManyTimes(arg: Int) -> [T] {
return Array<T>(count: arg, repeatedValue: T(arg))
}
func removeRandomElement(arg: [T]) -> [T] {
var output = [T]()
let randElemRemoved = Int(arc4random_uniform(UInt32(arg.count-1)))
for (i,element) in arg.enumerate() {
if i != randElemRemoved {
output.append(element)
}
}
return output
}
func countNumberOf42s(arg: [T]) -> Int {
var output = 0
for element in arg {
if element == T(42) {
output++
}
}
return output
}
}
最后,一些测试:
let myGenericExtensionUsedForDouble : SomeArrayProtocol<Array<Double>> = SomeArrayProtocol(SomeArrayGenericExtensions())
let myGenericExtensionUsedForFloat : SomeArrayProtocol<Array<Float>> = SomeArrayProtocol(SomeArrayGenericExtensions())
// let myGenericExtensionUsedForInt : SomeArrayProtocol<Array<Int>> = SomeArrayProtocol(SomeArrayGenericExtensions()) // Error! Int not SomeType, OK!
var myDoubleArr = [10.1, 42, 15.8, 42.0, 88.3]
let my10EntriesOfTenDoubleArr = myGenericExtensionUsedForDouble.repeatNumberNumberManyTimes(10) // ten 10:s
let myFloatArr : Array<Float> = [1.3, 5, 8.8, 13.0, 28, 42.0, 42.002]
let myIntArr = [1, 2, 3]
let a = myGenericExtensionUsedForDouble.countNumberOf42s(myDoubleArr) // 2
let b = myGenericExtensionUsedForFloat.countNumberOf42s(myFloatArr) // 1
myDoubleArr = myGenericExtensionUsedForDouble.removeRandomElement(myDoubleArr) // [10.1, 15.8, 42.0, 88.3]
我有点不确定上面的方法 2 是否真的对数组有一些实际应用(在米兰的报道中,他处理非序列类型,也许更有用);这是相当多的工作,但没有那么多额外的收益。然而,它可以是一个有启发性且非常有趣的练习:)
在 Swift 的更新版本中,可以这样写:
extension Array: SomeProtocol where Element == SomeType { ... }
不确定在哪个 Swift 版本中这成为可能,但以下在 Swift 4.1
中有效
class SomeType { }
protocol SomeProtocol {
func foo()
}
extension Array: SomeProtocol where Element == SomeType {
func foo() {
print("foo")
}
}
let arrayOfSome = [SomeType()]
arrayOfSome.foo() // prints "foo"
let arrayOfInt = [1,2,3]
arrayOfInt.foo() // Will not compile: '[Int]' is not convertible to 'Array<SomeType>'
(我知道这个问题特别要求Swift 2,但我添加这个以供参考)
我想扩展类型化数组 Array<SomeType>
以使其符合协议 SomeProtocol
。现在我知道您可以像下面这样扩展类型化数组:
extension Array where Element: SomeType { ... }
您还可以扩展对象以符合如下协议:
extension Array: SomeProtocol { ... }
但我无法弄清楚让类型化数组符合协议的正确语法是什么,例如:
extension (Array where Element: SomeType): SomeProtocol { ... }
有 Swift 2 位专家知道如何做到这一点吗?
您不能将大量逻辑应用于一致性。它要么符合,要么不符合。但是,您可以对扩展应用一些逻辑。下面的代码可以很容易地设置一致性的具体实现。哪个才是重点。
稍后用作类型约束。
class SomeType { }
这是你的协议
protocol SomeProtocol {
func foo()
}
这是协议的扩展。 foo()
在 SomeProtocol
扩展中的实现创建了一个默认值。
extension SomeProtocol {
func foo() {
print("general")
}
}
现在 Array
使用 foo()
的默认实现符合 SomeProtocol
。所有数组现在都有 foo()
作为方法,这不是很优雅。但它什么也没做,所以它不会伤害任何人。
extension Array : SomeProtocol {}
现在很酷的东西:
如果我们为 Array
创建一个带有 Element
类型约束的扩展,我们可以覆盖 foo()
extension Array where Element : SomeType {
func foo() {
print("specific")
}
}
测试:
let arrayOfInt = [1,2,3]
arrayOfInt.foo() // prints "general"
let arrayOfSome = [SomeType()]
arrayOfSome.foo() // prints "specific"
我自己一直在摆弄一些东西,有一些方法可以在某种程度上模仿您正在寻找的行为。
方法 #1
定义一个协议 SomeType
作为您希望 SomeProtocol
的 Array<SomeType>
扩展涵盖的类型的类型约束;其中后者包含一些您希望扩展的简洁方法的蓝图 Array
.
protocol SomeType {
var intValue: Int { get }
init(_ value: Int)
func *(lhs: Self, rhs: Self) -> Self
func +=(inout lhs: Self, rhs: Self)
}
extension Int : SomeType { var intValue: Int { return self } }
extension Double : SomeType { var intValue: Int { return Int(self) } }
/* Let's not extend 'Float' for now
extension Float : MyTypes { var intValue: Int { return Int(self) } } */
protocol SomeProtocol {
func foo<T: SomeType>(a: [T]) -> Int?
}
现在,您可以将 Array
扩展到 SomeProtocol
,并且通过使用 is
关键字,您可以断言您的泛型 T
(受 SomeType
) 和 Self
的元素通过使用 is
关键字属于同一类型,如果为真,则后跟显式转换:
extension Array : SomeProtocol {
func foo<T: SomeType>(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
}
}
我们现在用 SomeType
的元素扩展了 Array
,并在协议 SomeProtocol
中绘制了函数 foo(...)
。
/* 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 bar<U: SomeType> (arr1: [U], _ arr2: [U]) -> Int? {
return arr1.foo(arr2)
}
let myInt1d = bar(arr1d, arr2d) // -4, OK
let myInt1f = bar(arr1f, arr2f)
/* Compile time error: "Cannot convert value of type '[Float]'
to expected argument type '[_]'" */
好的!我们预计这里会出现最终编译时错误,因为 'Float' 不符合 SomeType
协议。
方法 #2
现在介绍另一种方法:我基于 this excellent post by Milen Dzhumerov 之后的泛型,此处针对数组进行了调整,并使用了一些不同的扩展方法示例。
对于这个例子,我们正在为 Array
:s 类型 Double
或 Float
实现一个 "generic" 协议扩展,由类型约束协议 SomeType
protocol SomeType {
init(_ value: Int)
init(_ value: Double)
init(_ value: Float)
func == (lhs: Self, rhs: Self) -> Bool
}
extension Double: SomeType {}
extension Float: SomeType {}
protocol GenericProtocol {
typealias AbstractType : SequenceType
func repeatNumberNumberManyTimes(arg: Int) -> AbstractType
func removeRandomElement(arg: AbstractType) -> AbstractType
func countNumberOf42s(arg: AbstractType) -> Int
}
使用结构将GenericProtocol
转发给AbstractType
(这里符合SequenceType
),并在后者中实现协议蓝图:
struct SomeArrayProtocol<T: SequenceType> : GenericProtocol {
private let _repeatNumberNumberManyTimes : (Int) -> T
private let _removeRandomElement : (T) -> T
private let _countNumberOf42s : (T) -> Int
init<P : GenericProtocol where P.AbstractType == T>(_ dep : P) {
_repeatNumberNumberManyTimes = dep.repeatNumberNumberManyTimes
_removeRandomElement = dep.removeRandomElement
_countNumberOf42s = dep.countNumberOf42s
}
func repeatNumberNumberManyTimes(arg: Int) -> T {
return _repeatNumberNumberManyTimes(arg)
}
func removeRandomElement(arg: T) -> T {
return _removeRandomElement(arg)
}
func countNumberOf42s(arg: T) -> Int {
return _countNumberOf42s(arg)
}
}
在另一个结构中实现 GenericProtocol
蓝图的实际方法,其中泛型现在被限制为 SomeType
类型约束(协议)。请注意,这是模仿您希望的冷杉(但直接无法实现)形式的部分 extension (Array where Element: SomeType): SomeProtocol { ... }
:
struct SomeArrayGenericExtensions<T: SomeType> : GenericProtocol {
typealias AbstractType = Array<T>
func repeatNumberNumberManyTimes(arg: Int) -> [T] {
return Array<T>(count: arg, repeatedValue: T(arg))
}
func removeRandomElement(arg: [T]) -> [T] {
var output = [T]()
let randElemRemoved = Int(arc4random_uniform(UInt32(arg.count-1)))
for (i,element) in arg.enumerate() {
if i != randElemRemoved {
output.append(element)
}
}
return output
}
func countNumberOf42s(arg: [T]) -> Int {
var output = 0
for element in arg {
if element == T(42) {
output++
}
}
return output
}
}
最后,一些测试:
let myGenericExtensionUsedForDouble : SomeArrayProtocol<Array<Double>> = SomeArrayProtocol(SomeArrayGenericExtensions())
let myGenericExtensionUsedForFloat : SomeArrayProtocol<Array<Float>> = SomeArrayProtocol(SomeArrayGenericExtensions())
// let myGenericExtensionUsedForInt : SomeArrayProtocol<Array<Int>> = SomeArrayProtocol(SomeArrayGenericExtensions()) // Error! Int not SomeType, OK!
var myDoubleArr = [10.1, 42, 15.8, 42.0, 88.3]
let my10EntriesOfTenDoubleArr = myGenericExtensionUsedForDouble.repeatNumberNumberManyTimes(10) // ten 10:s
let myFloatArr : Array<Float> = [1.3, 5, 8.8, 13.0, 28, 42.0, 42.002]
let myIntArr = [1, 2, 3]
let a = myGenericExtensionUsedForDouble.countNumberOf42s(myDoubleArr) // 2
let b = myGenericExtensionUsedForFloat.countNumberOf42s(myFloatArr) // 1
myDoubleArr = myGenericExtensionUsedForDouble.removeRandomElement(myDoubleArr) // [10.1, 15.8, 42.0, 88.3]
我有点不确定上面的方法 2 是否真的对数组有一些实际应用(在米兰的报道中,他处理非序列类型,也许更有用);这是相当多的工作,但没有那么多额外的收益。然而,它可以是一个有启发性且非常有趣的练习:)
在 Swift 的更新版本中,可以这样写:
extension Array: SomeProtocol where Element == SomeType { ... }
不确定在哪个 Swift 版本中这成为可能,但以下在 Swift 4.1
中有效class SomeType { }
protocol SomeProtocol {
func foo()
}
extension Array: SomeProtocol where Element == SomeType {
func foo() {
print("foo")
}
}
let arrayOfSome = [SomeType()]
arrayOfSome.foo() // prints "foo"
let arrayOfInt = [1,2,3]
arrayOfInt.foo() // Will not compile: '[Int]' is not convertible to 'Array<SomeType>'
(我知道这个问题特别要求Swift 2,但我添加这个以供参考)