Can't extend generic struct for specific type

2019-06-09 07:16发布

Wanted to toy with adding some sugar in Swift3. Basically, I wanted to be able to do something like:

let randomAdjust = (-10...10).random

To do that, I decided I would need to extend ClosedRange. But then found it would probably be even better for my case, I really just plan on doing Int's for now, to use CountableClosedRange. My latest of multiple attempts looked like:

extension CountableClosedRange where Bound == Int {
    var random:Int {
        return Int(arc4random_uniform(UInt32(self.count) + 1)) + self.lowerBound
    }
}

But the playground complains:

error: same-type requirement makes generic parameter 'Bound' non-generic
extension CountableClosedRange where Bound == Int {

I don't even know what it's telling me there.

标签: swift3
2条回答
一纸荒年 Trace。
2楼-- · 2019-06-09 07:52

The way this roadblock is commonly encountered is when attempting to extend Array. This is legal:

extension Array where Element : Comparable {
}

But this is illegal:

extension Array where Element == Int {
}

The compiler complains:

Same-type requirement makes generic parameter 'Element' non-generic

The problem is the use of == here in combination with Array's parameterized type Element, because Array is a generic struct.

One workaround with Array is to rise up the hierarchy of Array's inheritance to reach something that is not a generic struct:

extension Sequence where Iterator.Element == Int {
}

That's legal because Sequence and Iterator are generic protocols.

Another solution, though, is to rise up the hierarchy from the target type, namely Int. If we can find a protocol to which Int conforms, then we can use the : operator instead of ==. Well, there is one:

extension CountableClosedRange where Bound : Integer {
}

That's the real difference between our two attempts to implement random on a range. The reason your attempt hits a roadblock and mine doesn't is that you are using == whereas I am using :. I can do that because there's a protocol (FloatingPoint) to which Double conforms.

But, as you've been told, with luck all this trickery will soon be a thing of the past.

查看更多
Root(大扎)
3楼-- · 2019-06-09 07:59

In Swift 4, what you are attempting is now completely supported. Hooray!

Example in Swift docs: https://docs.swift.org/swift-book/LanguageGuide/Generics.html#ID553

查看更多
登录 后发表回答