键路径值类型 'Int' 无法转换为上下文类型 'String'
Key path value type 'Int' cannot be converted to contextual type 'String'
我正在尝试将包含 KeyPath 和一种排序顺序类型的多个元组传递给应该进行排序的方法。
我有这个方法:
extension Array {
mutating func sort<T: Comparable>(by criteria: (path: KeyPath<Element, T>, order:OrderType)...) {
criteria.forEach { path, order in
//...
sort { first, second in
order.makeComparator()(
first[keyPath: path],
second[keyPath: path]
)
}
}
}
}
我是这样使用它的:
var posts = BlogPost.examples
posts.sort(by:(path:\.pageViews, order: .asc), (path:\.sessionDuration, order: .desc))
现在,因为 pageViews
和 sessionDuration
属性都是 integers
,这将起作用。
但是如果我想传递两个不同类型的属性(比如 String
和 Int
),我会得到这个错误:
Key path value type 'Int' cannot be converted to contextual type 'String'
这是代码的其余部分,但我想不是那么相关:
enum OrderType: String {
case asc
case desc
}
extension OrderType {
func makeComparator<T: Comparable>() -> (T, T) -> Bool {
switch self {
case .asc:
return (<)
case .desc:
return (>)
}
}
}
我应该如何定义排序方法以便它接受异构 键路径?
目前还没有可变参数泛型,因此您需要编写一个 AnyComparable
类型的橡皮擦。这个改编自这个 post .
struct AnyComparable: Equatable, Comparable {
private let lessThan: (Any) -> Bool
private let value: Any
private let equals: (Any) -> Bool
public static func == (lhs: AnyComparable, rhs: AnyComparable) -> Bool {
lhs.equals(rhs.value) || rhs.equals(lhs.value)
}
public init<C: Comparable>(_ value: C) {
self.value = value
self.equals = { [=10=] as? C == value }
self.lessThan = { ([=10=] as? C).map { value < [=10=] } ?? false }
}
public static func < (lhs: AnyComparable, rhs: AnyComparable) -> Bool {
lhs.lessThan(rhs.value) || (rhs != lhs && !rhs.lessThan(lhs.value))
}
}
这样,您可以将 sort
方法签名写为:
mutating func sort(by criteria: (path: KeyPath<Element, AnyComparable>, order:OrderType)...) {
}
为了方便我们传递类型为AnyComparable
的关键路径,我们可以做一个扩展:
extension Comparable {
// this name might be too long, but I'm sure you can come up with a better name
var anyComparable: AnyComparable {
.init(self)
}
}
现在我们可以做:
someArray.sort(by: (\.key1.anyComparable, .asc), (\.key2.anyComparable, .asc))
我正在尝试将包含 KeyPath 和一种排序顺序类型的多个元组传递给应该进行排序的方法。
我有这个方法:
extension Array {
mutating func sort<T: Comparable>(by criteria: (path: KeyPath<Element, T>, order:OrderType)...) {
criteria.forEach { path, order in
//...
sort { first, second in
order.makeComparator()(
first[keyPath: path],
second[keyPath: path]
)
}
}
}
}
我是这样使用它的:
var posts = BlogPost.examples
posts.sort(by:(path:\.pageViews, order: .asc), (path:\.sessionDuration, order: .desc))
现在,因为 pageViews
和 sessionDuration
属性都是 integers
,这将起作用。
但是如果我想传递两个不同类型的属性(比如 String
和 Int
),我会得到这个错误:
Key path value type 'Int' cannot be converted to contextual type 'String'
这是代码的其余部分,但我想不是那么相关:
enum OrderType: String {
case asc
case desc
}
extension OrderType {
func makeComparator<T: Comparable>() -> (T, T) -> Bool {
switch self {
case .asc:
return (<)
case .desc:
return (>)
}
}
}
我应该如何定义排序方法以便它接受异构 键路径?
目前还没有可变参数泛型,因此您需要编写一个 AnyComparable
类型的橡皮擦。这个改编自这个 post
struct AnyComparable: Equatable, Comparable {
private let lessThan: (Any) -> Bool
private let value: Any
private let equals: (Any) -> Bool
public static func == (lhs: AnyComparable, rhs: AnyComparable) -> Bool {
lhs.equals(rhs.value) || rhs.equals(lhs.value)
}
public init<C: Comparable>(_ value: C) {
self.value = value
self.equals = { [=10=] as? C == value }
self.lessThan = { ([=10=] as? C).map { value < [=10=] } ?? false }
}
public static func < (lhs: AnyComparable, rhs: AnyComparable) -> Bool {
lhs.lessThan(rhs.value) || (rhs != lhs && !rhs.lessThan(lhs.value))
}
}
这样,您可以将 sort
方法签名写为:
mutating func sort(by criteria: (path: KeyPath<Element, AnyComparable>, order:OrderType)...) {
}
为了方便我们传递类型为AnyComparable
的关键路径,我们可以做一个扩展:
extension Comparable {
// this name might be too long, but I'm sure you can come up with a better name
var anyComparable: AnyComparable {
.init(self)
}
}
现在我们可以做:
someArray.sort(by: (\.key1.anyComparable, .asc), (\.key2.anyComparable, .asc))