Ответ 1
Решение времени компиляции
extension _ArrayType where Generator.Element == Any {
func sortQ() -> Any? {
return nil
}
}
extension _ArrayType where Generator.Element: Comparable {
func sortQ() -> [Self.Generator.Element] {
return self.sort(<)
}
}
// Because Bool is not comparable by default...
extension Bool: Comparable {
}
public func < (lhs: Bool, rhs: Bool) -> Bool {
return !lhs && rhs // or Int(lhs) < Int(rhs)
}
[10, 11, 0, 2, -1].sortQ() //[-1, 0, 2, 10, 11]
["Red", "Green", "Blue"].sortQ() //["Blue", "Green", "Red"]
[true, false, true, true].sortQ() //[false, true, true, true]
[CGPointZero, CGPoint(x:1, y:1)].sortQ() //nil
[10, "Hello"].sortQ() //nil
Решения времени выполнения:
UPDATE
Здесь не конечное состояние. Проблема заключается в том, что кастинг сопоставим. ИМХО это невозможно. До сих пор я не знал о трюке с дополнительным типом. Во всяком случае, даже литье мета-типа невозможно, потому что тип неизвестен до выполнения. Мое слабое обходное решение - список поддерживаемых сопоставимых типов:
extension _ArrayType {
func sortQ() -> [Generator.Element]? {
var arrayOK = true
let sortedArray = sort { (firstElement, secondElement) -> Bool in
guard arrayOK else {
return false
}
let f = Mirror(reflecting: firstElement)
let s = Mirror(reflecting: secondElement)
guard f.subjectType == s.subjectType else {
arrayOK = false
return false
}
switch String(f.subjectType) {
case "Int":
return (firstElement as! Int) < (secondElement as! Int)
case "String":
return (firstElement as! String) < (secondElement as! String)
case "Bool":
return (firstElement as! Bool) < (secondElement as! Bool)
default:
arrayOK = false
return false
}
}
return arrayOK ? sortedArray : nil
}
}
ОБНОВЛЕНИЕ 2
Второй вариант - иметь сопоставимый протокол, определенный по-разному (AnyComparable
). К сожалению, это означает создание расширений для всех типов Comparable.
Иначе нет способа, во время компиляции компилятор может найти правильную функцию/оператор (поскольку он не знает типы раньше времени).
Итак, у вас есть два варианта:
- если у вас есть представление о типах, которые вы сравнивали и определяете их явно (обновление 1).
- Использовать интерфейс, который не использует Self тип (обновление 2).
IMHO нет другого решения
protocol AnyComparable {
func compareTo(second: Any) -> Bool
}
extension AnyComparable where Self: Comparable {
func compareTo(second: Any) -> Bool {
if let secondSameType = second as? Self {
return self < secondSameType
}
return false
}
}
extension Int: AnyComparable {
}
extension String: AnyComparable {
}
extension Bool: AnyComparable {
}
extension _ArrayType {
func sortQ() -> [Generator.Element]? {
var arrayOK = true
var wantedType: Any.Type?
let sortedArray = sort { (firstElement, secondElement) -> Bool in
guard arrayOK else {
return false
}
if wantedType == nil {
wantedType = Mirror(reflecting: firstElement).subjectType
}
guard let f = firstElement as? AnyComparable where wantedType == Mirror(reflecting: secondElement).subjectType else {
arrayOK = false
return false
}
return f.compareTo(secondElement)
}
return arrayOK ? sortedArray : nil
}
}