Я сам обдумывал это, и есть некоторые способы несколько подражать поведению, которое вы сейчас oking для.
Подход № 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
) и элементы 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
}
}
Теперь мы расширенная Array
с элементами SomeType
с функцией foo(...)
blueprin в протоколе 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 '[_]'" */
Ok! Мы ожидали окончательной ошибки времени компиляции, так как «Float» не соответствует протоколу SomeType
.
Подход № 2
Теперь для другого подхода: Я основан на дженерики, которые следуют по this excellent post by Milen Dzhumerov, здесь приспособлены для массива и с некоторыми примерами различных методов расширения.
В этом примере мы реализуем «общее» расширение протокола для Array
: S типа Double
или 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
}
}
Наконец, некоторые тесты:
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 выше на самом деле некоторые практические приложения для массивов или нет (в покрытии Милан он относится к типам без последовательности, возможно, более полезен); это довольно много работы для не столько дополнительного взрыва для доллара. Тем не менее, это может быть поучительным и довольно развлекательным упражнением :)
Посмотрите на протокол StringType в этом ответе, чтобы расширить массив строк http://stackoverflow.com/a/33862452/2303865 –
Расширение типа ' Массив с ограничениями не может иметь оговорку о наследовании. логики нет. можете ли вы предоставить нам полезный пример? – user3441734
@JamesHu У вас было время посмотреть и дать ответ нашим ответам ниже? – dfri