はじめに
Goには「1つの文字」を表現するためのrune型があります。筆者は普段Javaを書いているため「char型みたいなものか」と思っていましたが、少し扱いが異なる点について、(忘れるうちに)まとめてみました。
対象読者
- Javaでの開発経験があり、これからGo言語を学び始めようとしている方
- Javaのchar型と、Goのrune型との違いを理解したい方
- Javaのchar型やサロゲートペアの仕組みについて、改めて復習したい方
Javaのchar型はUTF-16コード単位
Javaの文字リテラルが表せるのはUTF-16の1コード単位(code unit)に限られます。
つまり、charで表せるのは全UnicodeU+0000〜U+10FFFFのうち、U+0000~U+FFFF のみとなります(U+10000~U+10FFFFは扱えない)。
これは、Javaが設計された当初のUnicodeが16ビットであったためですが、時が経つにつれて扱える文字数が増加したという歴史的背景があります(詳細は割愛します)
そのため、charに「😀」(U+1F600)のような絵文字を指定するとコンパイルエラーになってしまいます。
public class Main {
public static void main(String[] args) {
char c = '😀'; // コンパイルエラー
System.out.println(c);
}
}
Javaでこれらの文字を扱う方法としては、主に以下2つの方法があります。
- サロゲートペア(2つのchar)として表す
- Unicodeコードポイント(整数)として扱う
public class Main {
public static void main(String[] args) {
// サロゲートペアを使って表す方法
String surrogate = "\uD83D\uDE00"; // または、String surrogate = "😀";
System.out.println(surrogate); // 😀
// Unicodeコードポイント(整数)で表す方法
int codePoint = 0x1F600; // または、int codePoint = 128512;
System.out.println(new String(Character.toChars(codePoint))); // 😀
}
}
Goのrune型はUnicodeコードポイントそのもの
一方、Goのrune型はint32型の別名(つまりは整数型)で、Unicodeコードポイントそのものを表します。
つまり、Javaで2つのcharが必要だった絵文字も、Goでは1つのruneで表現できます。
package main
import "fmt"
func main() {
var r rune = '😀' // runeリテラル
fmt.Println(r) // 128512
fmt.Printf("%c\n", r) // 😀
}
また、UnicodeコードポイントでU+10000以上のruneを表現する場合は、主に以下2つの方法があります。
- Unicodeエスケープ(
\U)のruneリテラルで表す方法 - 整数リテラルで表す方法
package main
import "fmt"
func main() {
// Unicodeエスケープ(\U)のruneリテラルで表す方法
var r2 rune = '\U0001F600' // 32ビットUnicodeコードポイント(16進数で指定したruneリテラル)
fmt.Println(r2) // 128512
fmt.Printf("%c\n", r2) // 😀
// 整数リテラルで表す方法
var r3 rune = 0x1F600 // または、var r3 rune = 128512
fmt.Println(r3) // 128512
fmt.Printf("%c\n", r3) // 😀
}
まとめ
最後に、Javaのcharと、Goのruneの共通点や相違点についてまとめます。
どちらもUnicodeコードポイントを整数として扱えますが、Goのruneは1つで任意のUnicodeコードポイントを表現できるのに対し、JavaのcharはU+10000以上の文字については、2つのcharで表現する必要があるため、注意しましょう。
charやruneは極力使わないでStringを使いましょう。
| 項目 | Java (char) |
Go (rune) |
|---|---|---|
| 意味するもの | UTF-16コード単位 | Unicodeコードポイント |
| 表現できる範囲 |
U+0000 ~ U+FFFF
|
U+0000 ~ U+10FFFF(Unicode全範囲) |
| 絵文字 (例: '😀') | サロゲートペアにすれば扱える | 扱える |
| Unicodeコードポイント(整数型) | int型にすれば扱える | 扱える |
参考