How to define a method that operates on aString or aString.reversed(): I think these are BidirectionalCollection or Collection of Character?

I need a method that can be called like this:

let s = "some string"
let a = lookingForSign(s)
// or in reverse:
let b = lookingForSign(s.reversed())

I think I need something that works on a BidirectionalCollection or Collection of Character:

class Foo {
    ...
    // I'm not able to come up with the right signature here:
    func lookingForSign<S: BidirectionalCollection>lookingForSign(_ text: S) -> String? where ??? {  // how to define this?
        // Element is Character...
            guard let signIndex = text.prefix(while: { !$0.isASCIIDigit }).firstIndex(where: { allowedSigns.contains(String($0)) }) else {
                return nil
            }
            return String(text[signIndex])
    }
}
1 Like

Try this:

func lookingForSign<S: BidirectionalCollection>(_ text: S) -> String?
where S.Element == Character

:+1:

I thought I did that, guess not..

BTW: Collection works as well
thanks!

1 Like

Be mindful that Collection.reversed uses Sequence.reversed, which creates a new array and copies the entire collection.

1 Like

Ah, thank you!

In my case, since I don't want text.reversed() to create a new Array copying the original String over, I should stick to only allow BidirectionalCollection for my method?

I'm not sure if I am 100% understand:

for this call:

let b = lookingForSign(s.reversed())

if I define my func this way:

func lookForSign<S: Collection>(_ text: S) -> String? where S.Element == Character {
     // is text here a new Array copying everything over from the original String?
    // even though s was a String which is BidirectionalCollection?
}

vs.

func lookingForSign<S: BidirectionalCollection>(_ text: S) -> String?
where S.Element == Character {
    // text here is a `ReversedCollection` which "reference" the original s String, no copying?
}

Okay, I'm wrong. For my case, either Collection or BidirectionalCollection end up with ReversedCollection<String>:

var greeting = "Hello, playground"

aaa(greeting.reversed())
bbb(greeting.reversed())

func aaa<S: BidirectionalCollection>(_ text: S) where S.Element == Character {
    print(" >> aaa: ", type(of: text))  //  >> aaa:  ReversedCollection<String>
}


func bbb<S: Collection>(_ text: S) where S.Element == Character {
    print(" >> bbb", type(of: text))    //  >> bbb ReversedCollection<String>
}

Oh, I missed that you reversed the string outside of lookingForSign. In that case Swift will use a more specific version of reversed available to String, which are Sequence.reversed and BidirectionalCollection.reversed. Since BidiCol refines Seq, BidiCol.reversed are selected.

The problem I mention is more akin to this:

var greeting = "Hello, playground"

aaa(greeting)
bbb(greeting)

// Reverse inside

func aaa<S: BidirectionalCollection>(_ text: S) where S.Element == Character {
    print(" >> aaa: ", type(of: text.reversed()))
}


func bbb<S: Collection>(_ text: S) where S.Element == Character {
    print(" >> bbb: ", type(of: text.reversed()))
}

In this case, bbb.text can only use Sequence.reversed (it doesn't know that S: BidiCol, and reversed isn't a protocol requirement either).

1 Like

ok. so it's okay for my use case to use Collection conformance requirement.

Terms of Service

Privacy Policy

Cookie Policy