Home > Software design >  swift constrain generic function to non-protocol type without casting
swift constrain generic function to non-protocol type without casting

Time:03-03

I'm writing a parsing library - I have a situation where I want to be able to turn any parser that spits out a list of characters int a parser that spits out a string - eg so I can say something like:

    let parseWhitespace = Parse.any_of( " ", "\t").many().text()

so I naively wrote:

extension Parser
{
    public func text() -> Parser<String> where T : [Character]
    {
        map( {String($0)} )
    }
}

but that got upset with me - saying "type T constrained to non-protocol non type class"

A bit of googling later - and I came up with the craziest hack, which is the following:

public protocol CharacterArray {}
extension Array : CharacterArray where Array.Element == Character
{
}

extension Parser
{
    public func text() -> Parser<String> where T : CharacterArray
    {
        map( { String(($0 as? [Character])!) })
    }
}

which works. But is ridiculous - and worst - it has a cast in it. Is there any way of doing this without a cast?

CodePudding user response:

When you want to constrain an associated type to be an exact concrete type, you use == instead of :.

public func text() -> Parser<String> where T == [Character]
                                       //    ^^ instead of a colon
  • Related