Home > Software engineering >  Swift - Problems with KeyPath in protocols and extension
Swift - Problems with KeyPath in protocols and extension

Time:07-10

I'm using Swift 5.7, Xcode 14.0 beta (14A5228q)

I'm trying to get an element knowing the ID (Element conforms Identifiable protocol) in an Tree Structure implementing from arrays, I mean, I had one array with Identifiable values/objects and the element has a property (see the reversePath) that is an array with object with the same kind of it self.

I don't know why de following code doesn't work.

extension Array where Element: Identifiable{
    subscript(index: Element.ID?, recursivePath: KeyPath<Element,Array<Element>>) -> Element?{
        if( index != nil){
            for e in self{
                if(e.id == index){
                    return e
                }else{
                    let array: [any Identifiable] = e[keyPath: recursivePath] as [any Identifiable]
                    let ret = array[index: index, recursivePath: recursivePath]
                    if(ret != nil){
                        return ret
                    }
                }
            }
        }
        return  nil
    }
}

It's seems that

e[keyPath: recursivePath] as [any Identifiable]

doesn't recognise

extension Array where Element: Identifiable

CodePudding user response:

First, you don't need as [any Identifiable] here at all, and don't want it. That would force a copy of the array to box the elements in an existential wrapper.

But that's not the problem. You've just confused subscript parameters a little bit, because they don't work like function parameters. Instead of the external name automatically being the internal name (like in functions), subscript parameters default to having no external name. So:

Definition:                             Called as:
------------------------------------------------------
subscript(x: Int, y: Int) -> Int        xs[x, y]
subscript(x x: Int, y y: Int) -> Int    xs[x: x, y: y]

So to work they way you've written it, you need to change your signature to (notice the duplicated parameter names):

subscript(index index: Element.ID?, recursivePath recursivePath: KeyPath<Element,Array<Element>>) -> Element?{

With that, you can change the array assignment to:

let array = e[keyPath: recursivePath]

And it should compile. (I haven't dug into whether it will actually do what you want it to do, but it will compile.)

For more on subscript parameters, see Subscript Declarations in the Swift Language Reference:

Subscript parameters follow the same rules as function parameters, with two exceptions. By default, the parameters used in subscripting don’t have argument labels, unlike functions, methods, and initializers. However, you can provide explicit argument labels using the same syntax that functions, methods, and initializers use.

  • Related