创建一个 CountableClosedRange<Character>

JAL*_*JAL 4 swift

我试图扩展Character到符合Strideable以创建CountableClosedRangeCharacter类型。最后,我想要打印整个字母表的类似内容:

("A"..."Z").forEach{
    print($0)
}
Run Code Online (Sandbox Code Playgroud)

目前,我使用UnicodeScalar类型来计算两个字符之间的距离。因为Character类型中没有标量,所以我需要从字符创建一个字符串,获取第一个标量的值,并计算它们之间的距离:

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))
    }

}
Run Code Online (Sandbox Code Playgroud)

即使这样,我也会收到Character不符合协议Strideable_Strideable. 编译器似乎没有选择Stride随附的关联类型Strideable

public protocol Strideable : Comparable {

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

    // ...

}
Run Code Online (Sandbox Code Playgroud)

我错过了什么?

Ham*_*ish 6

如前所述,因为 aCharacter可以由多个 unicode 标量组成,所以您无法准确确定两个任意字符之间有多少不同的有效字符表示,因此不是符合Stridable.

一种方法是你的只是想打印出字母表问题是顺应UnicodeScalar,而不是CharacterStridable-让你与由单一的Unicode代码点表示的字符工作,并推动它们基于代码点。

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
    }
}
Run Code Online (Sandbox Code Playgroud)

现在您可以形成 a CountableClosedRange<UnicodeScalar>,并且可以自由地将每个单独的元素转换为 aCharacter或者String如果需要:

("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)}
Run Code Online (Sandbox Code Playgroud)