测试指向的 KeyPath 类型是否为 Set

huangapple go评论78阅读模式
英文:

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
    }
}

然后,让所有的KeyPaths都符合它:

extension KeyPath: CollectionQueryable { }

然后,在两种有效的情况下有条件地返回trueNSOrderedSetSet

extension KeyPath where Value == NSOrderedSet {

    var isToMany: Bool {
        return true
    }
}

extension KeyPath where Value: Set {

    var isToMany: Bool {
        return true
    }
}

但是编译器抱怨我没有在这里指定Set的泛型类型。如果我将其切换为Collection,编译器会非常高兴,但是这不会起作用,因为当ValueString时,它返回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 KeyPaths 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&lt;Root, Value&gt;(_ keyPath: KeyPath&lt;Root, Value&gt;) -&gt; Bool {
    return false
}

func isToMany&lt;Root&gt;(_ keyPath: KeyPath&lt;Root, NSOrderedSet&gt;) -&gt; Bool {
    return true
}

func isToMany&lt;Root, Element&gt;(_ keyPath: KeyPath&lt;Root, Set&lt;Element&gt;&gt;) -&gt; 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
}

huangapple
  • 本文由 发表于 2020年1月3日 18:18:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/59576774.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定