Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
870 views
in Technique[技术] by (71.8m points)

swift - Creating a CountableClosedRange<Character>

I am trying to extend Character to conform to Strideable in order to create a CountableClosedRange of Character types. In the end, I would like to have something like this which prints the whole alphabet:

("A"..."Z").forEach{
    print($0)
}

For the time being, I am using UnicodeScalar types to calculate the distance between two characters. Because a scalar isn't available from a Charactertype, I need to create a String from the Character, get the first scalar's value, and calculate the distance between them:

extension Character: Strideable {

    func distance(to other: Character) -> Character.Stride {
        return abs(String(self).unicodeScalars.first?.value - String(other).unicodeScalars.first!.value)
    }

    func advanced(by n: Character.Stride) -> Character {
        return Character(UnicodeScalar(String(self).unicodeScalars.first!.value + n))
    }

}

Even with this, I get the error that Character does not conform to protocol Strideable and _Strideable. The compiler does not appear to be picking up the Stride associated type which comes with Strideable:

public protocol Strideable : Comparable {

    /// A type that can represent the distance between two values of `Self`.
    associatedtype Stride : SignedNumber

    // ...

}

What am I missing?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

As already said, because a Character can be made up of multiple unicode scalars, you cannot accurately determine how many different valid character representations lie between two arbitrary characters, and is therefore not a good candidate for conformance to Stridable.

One approach to your problem of simply wanting to print out the alphabet is to conform UnicodeScalar, rather than Character, to Stridable – allowing you to work with characters that are represented by a single unicode code point, and advance them based on that code point.

extension UnicodeScalar : Strideable {

    public func distance(to other: UnicodeScalar) -> Int {
        return Int(other.value) - Int(self.value)
    }

    /// Returns a UnicodeScalar where the value is advanced by n.
    ///
    /// - precondition: self.value + n represents a valid unicode scalar.
    ///
    public func advanced(by n: Int) -> UnicodeScalar {
        let advancedValue = n + Int(self.value)
        guard let advancedScalar = UnicodeScalar(advancedValue) else {
            fatalError("(String(advancedValue, radix: 16)) does not represent a valid unicode scalar value.")
        }
        return advancedScalar
    }
}

Now you can form a CountableClosedRange<UnicodeScalar>, and can freely convert each individual element to a Character or String if desired:

("A"..."Z").forEach {

    // You can freely convert scalar to a Character or String
    print($0, Character($0), String($0))
}

// Convert CountableClosedRange<UnicodeScalar> to [Character]
let alphabetCharacters = ("A"..."Z").map {Character($0)}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...