0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[Swift] Character型リテラルを定義する

Last updated at Posted at 2025-11-24

目的

↑ この記事の続きとなります。

Swiftには、Character型を直接意味する リテラルは 存在しません。

つまり、C/C++言語のように、char型は 'A'(シングルクォーテーションで囲む)、string(char*)型は "A"(ダブルクォーテーションで囲む)といった書き方ができません。

標準で書ける(単純型の)リテラルは、
数値103.14 か、文字列"abcdefg" の タイプしか存在しません。

敢えて ‘風な’と付け加えた理由は、実際の型は ExpressibleByXXXXLiteralプロトコル によって定義され、見た目と実態は必ずしも一致しないからです。例えば、数値を書いて 文字列型にすることもできます。

  • 例;数値を文字列型にする
    let a: MyStringLiteral = 123
    print(type(of: a), a.debugDescription)
    //String "123"
    


今回のテーマは、「Character型リテラルを定義する」です。
しかし、ExpressibleByXXXXLiteralプロトコル を定義してCharacter型にすることではありません。型アンテーションは すでにあります。

  • 例;Character型とする
    let a: Character = "a"
    print(type(of: a), a.debugDescription)
    //Character "a"
    


理想は、(シングルクォーテーションで囲む)'a'と書きたいところですが、これは 現在のSwift言語仕様上 無理な話なので、PythonやC++などのRaw文字列風な書き方で実現したいと思います。

  • 目指す書き方
    let a = r"a"
    

実装の検討

関数的な書き方なら、今でも普通に書けます。

  • let a = Character("a")	// Character.init
    


Characterが長いならTypealiasや関数定義で 1文字にできます。

  • typealias C = Character
    let a = C("a")	// Character.init
    


あくまで 文字列リテラルで表現したいので、次の書式で書ける方法を考えます。

  • let a = c"a"
    

    しかし、現在のSwift言語仕様上、このままは 無理ですね。


Cの代わりに 何らかの演算子を使った表現なら、

  • let a = ^"a"
    

    この書式であれば、文字列に対する^前置演算子を定義することで 実現できます。

    prefix operator ^
    func ^(arg: String) -> Character {
        if arg.isEmpty { Character(UnicodeScalar(0)) }
        else { Character(String(arg.first!)) }
    }
    
    let a = ^"a"
    print(type(of: a), a.debugDescription)
    //Character "a"
    

見た目はOKですが、次の点を変更します。
  1. ^を含む既存の演算子の利用は、他の演算子拡張との兼ね合いで避けたい
  2. func定義をインライン化して、少しでも変換ロスをなくしたい

最終的な定義

・ Character Literal

一部のUnicode文字を 演算子として定義できる言語仕様を活かして、以下のように定義しました。

  • prefix operator © // keystroke option+G
    @inlinable @inline(__always)
    prefix func ©(arg: String) -> Character {
        if arg.isEmpty { Character(UnicodeScalar(0)) }
        else { Character(String(arg.first!)) }
    }
    @inlinable @inline(__always)
    prefix func ©(arg: Int) -> Character {
        if let scalar = UnicodeScalar(arg) { Character(scalar) }
        else { Character(UnicodeScalar(0)) }
    }
    
    • 演算子は©(コピーライトマーク)とする
      Macであれば、⌥Goption + G)でタイプ可
    • インライン展開を指示(実効性は不明)
    • IntでUnicode値を指定する©前置演算子も定義

  • 使い方

    let a = ©"A"
    print(type(of: a), a.debugDescription)
    //Character "A"
    
    let constellation = 0x2648 ... 0x2653
    for c in constellation {
        print("U+\(String(format: "%X", c)) \(©c)")
    }
    //U+2648 ♈
    //U+2649 ♉
    //U+264A ♊
    //U+264B ♋
    //U+264C ♌
    //U+264D ♍
    //U+264E ♎
    //U+264F ♏
    //U+2650 ♐
    //U+2651 ♑
    //U+2652 ♒
    //U+2653 ♓
    



・ Character型をStrideableに準拠させる②

前回の記事で書いたコードは、ASCIIコード限定でした。今回は、これを Unicode 全体に拡張します。

  • extension Character: @retroactive Strideable {
        public func advanced(by n: Int) -> Self {
            var nextValue = self.value + n
            while 0 < nextValue && nextValue <= 0x10FFFF {
                if let scalar = UnicodeScalar(nextValue) {
                    return Character(scalar)
                }
                nextValue &+= 1
            }
            return Character(UnicodeScalar(0))
        }
        public func distance(to x: Self) -> Int {
            return x.value - self.value
        }
        var value: Int { Int(self.unicodeScalars.first!.value) }
    }
    

  • 使い方
    let constellation = ©0x2648 ... ©0x2653
    for c in constellation {
        print("U+\(String(format: "%X", c.value)) \(c)")
    }
    //U+2648 ♈
    //U+2649 ♉
    //U+264A ♊
    //U+264B ♋
    //U+264C ♌
    //U+264D ♍
    //U+264E ♎
    //U+264F ♏
    //U+2650 ♐
    //U+2651 ♑
    //U+2652 ♒
    //U+2653 ♓
    

結果

Character型リテラルを定義することが目的でしたが、厳密には達成できていません。しかし、「コードを書く上での見た目が同じ」という点にて 達成できたと評価します(自己マンです)。

  • let a = c"a"	//目指す書き方
    let a = ©"A"	//今回実現した書き方
    




以上

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?