英文:
Test if type pointed to by KeyPath is a Set
问题
给定一个KeyPath<Root, Value>
,有没有一种干净的方法来测试Value.self
是否是一个Set
?对于Core Data,我想要指定一个API,该API接受一个KeyPath<Root, Value>
,并且可以使用它来确定它是否是一个toMany
关系。到目前为止,我最好的尝试是指定一个协议:
extension CollectionQueryable {
var isToMany: Bool {
return false
}
}
然后,让所有的KeyPath
s都符合它:
extension KeyPath: CollectionQueryable { }
然后,在两种有效的情况下有条件地返回true
:NSOrderedSet
和Set
。
extension KeyPath where Value == NSOrderedSet {
var isToMany: Bool {
return true
}
}
extension KeyPath where Value: Set {
var isToMany: Bool {
return true
}
}
但是编译器抱怨我没有在这里指定Set
的泛型类型。如果我将其切换为Collection
,编译器会非常高兴,但是这不会起作用,因为当Value
是String
时,它返回true
,在这种情况下是错误的。
英文:
Given a KeyPath<Root, Value>
, is there a clean way to test if Value.self
is a Set
? For Core Data, I want to specify an API that takes a KeyPath<Root, Value>
, and can use this to determine if it's a toMany
relationship. My best attempt thus far was to specify a protocol:
extension CollectionQueryable {
var isToMany: Bool {
return false
}
}
Then, have all KeyPath
s conform to it:
extension KeyPath: CollectionQueryable { }
Then conditionally return true
for the two cases that are valid: NSOrderedSet
and Set
.
extension KeyPath where Value == NSOrderedSet {
var isToMany: Bool {
return true
}
}
extension KeyPath where Value: Set {
var isToMany: Bool {
return true
}
}
But the compiler is complaining that I'm not specifying the generic type of the Set
here. If I switch this to Collection
, the compiler is quite happy, but this won't work because it returns true
when Value
is a String
which is quite wrong in this case.
答案1
得分: 1
你可以通过使用重载函数来反转泛型的注入方式。这将允许你避免缺少泛型的问题,并且在行为上也具有明确的优势。
func isToMany<Root, Value>(_ keyPath: KeyPath<Root, Value>) -> Bool {
return false
}
func isToMany<Root>(_ keyPath: KeyPath<Root, NSOrderedSet>) -> Bool {
return true
}
func isToMany<Root, Element>(_ keyPath: KeyPath<Root, Set<Element>>) -> Bool {
return true
}
英文:
You could inverse how the generics are injected by using overloaded functions. This will allow you to avoid the missing generics problem, and also has the benefit of being explicit behaviourally speaking.
func isToMany<Root, Value>(_ keyPath: KeyPath<Root, Value>) -> Bool {
return false
}
func isToMany<Root>(_ keyPath: KeyPath<Root, NSOrderedSet>) -> Bool {
return true
}
func isToMany<Root, Element>(_ keyPath: KeyPath<Root, Set<Element>>) -> Bool {
return true
}
答案2
得分: 0
我最终使用了一个在`Optional`帖子中找到的类型擦除技术,以实现我想要的只给定`Type`信息:
```swift
protocol ToManyProtocol {
static var elementType: Any.Type { get }
}
extension Set: ToManyProtocol {
static var elementType: Any.Type {
return Element.self
}
}
现在我可以通过测试类型是否为ToManyProtocol
来测试某物是否是toMany
:
var isToMany: Bool {
return Value.self is ToManyProtocol.Type
}
<details>
<summary>英文:</summary>
I ended up using a type-erasure technique found on one of the `Optional` posts to achieve what I wanted given only `Type` information:
```swift
protocol ToManyProtocol {
static var elementType: Any.Type { get }
}
extension Set: ToManyProtocol {
static var elementType: Any.Type {
return Element.self
}
}
Now I can test if something is toMany
by testing whether the Type is ToManyProtocol
:
var isToMany: Bool {
return Value.self is ToManyProtocol.Type
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论