我想扩展一个类型化数组Array<SomeType>
,使其符合协议SomeProtocol
。现在我知道你可以扩展一个类型化的数组,如下所示:
extension Array where Element: SomeType { ... }
你还可以扩展一个对象以符合这样的协议:
extension Array: SomeProtocol { ... }
但我无法弄清楚使用类型数组符合协议的正确语法是什么,例如:
extension (Array where Element: SomeType): SomeProtocol { ... }
任何Swift 2专家都知道如何做到这一点?
答案 0 :(得分:4)
您不能将大量逻辑应用于一致性。它要么符合要么不符合要求。但是,您可以对扩展应用一些逻辑。下面的代码可以轻松设置一致性的特定实现。哪个是重要的部分。
稍后将其用作类型约束。
protocol SomeProtocol {
func foo()
}
这是你的协议
foo()
这是协议的扩展。在SomeProtocol
扩展名中extension SomeProtocol {
func foo() {
print("general")
}
}
的实施会创建默认值。
Array
现在SomeProtocol
使用foo()
的默认实现符合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"
试验:
static void Main(string[] args)
{
Thread.Sleep(DateTime.Today.AddDays(1) - DateTime.Now);
Console.WriteLine("It's about midnight, I go to sleep");
}
答案 1 :(得分:2)
我自己一直在摆弄一些人,并且有一些方法可以模仿你正在寻找的行为。
方法#1
定义协议SomeType
,作为Array<SomeType>
SomeProtocol
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
(受{{1}约束} {} Self
的元素使用is
关键字属于同一类型,如果为true,则后跟显式转换:
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
}
}
我们现在已扩展Array
,其中SomeType
元素的功能foo(...)
已在协议SomeProtocol
中进行了蓝图打印。
/* 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
或Double
的{{1}}实现“通用”协议扩展,由类型约束协议Float
表示
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
}
}
我有点不确定上面的方法2是否实际上对数组有一些实际的应用(在Milans报道中,他对待非序列类型,可能更有用);对于降压而言,没有那么多额外的帮助,这是相当多的工作。但是,它可以是一种有益的,非常有趣的练习:)
答案 2 :(得分: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,但我将其添加以供参考)