给定一个定义如下的数组
- let list: [Any]
我想把它分类
>其中的所有值都具有相同的Element类型
> AND元素是可比的.
当它应该返回排序的数组
所以我需要一个函数,当数组以如下的方式填充时
- let list: [Any] = [10,11,2,-1]
- let list: [Any] = ["Red","Green","Blue"]
- let list: [Any] = [true,false,true,true]
确实返回排序的数组.
当它应该返回零
另一方面,当列表包含以下示例之一时
- let list: [Any] = [CGPointZero,CGPoint(x:1,y:1)] // CGPoint is not comparable
- let list: [Any] = [10,"Hello"] // Values of different types
我想要nil作为返回值.
任何想法?
编译时间解决方案
- 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,-1].sortQ() //[-1,10,11]
- ["Red","Blue"].sortQ() //["Blue","Red"]
- [true,true].sortQ() //[false,true]
- [CGPointZero,y:1)].sortQ() //nil
- [10,"Hello"].sortQ() //nil
运行时解决方案:
UPDATE
这是非最终状态.问题是与铸造相当. IMHO是不可能的.到目前为止,我不知道可选类型的技巧.无论如何,即使是转换元类型也是不可能的,因为类型在运行时才是不知道的.我的弱化解决方案是列出支持的可比类型:
- 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).不幸的是,这意味着创建所有可比较类型的扩展.
否则没有办法,在编译时,编译器可以找到正确的函数/运算符(因为它不提前知道类型).
所以你有两个选择:
>如果你有一些想要比较和定义的类型
他们明确(更新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
- }
- }