rune型は単なるint32のエイリアス
runeの疑問
rangeでrune型を取り出す際
func main() { str := "A" var x rune for i, v := range str { x = v x = str[i] // 代入出来ない } }
値はrune型。けどインデックスアクセスで取得した値はrune型じゃない。
どちらもstring()
でキャストしたらAなのに何で?
型を調べる
func main() { str := "A" for i, v := range str { fmt.Printf("str[i] value: %v, type: %T \n" , str[i], str[i]) fmt.Printf("v value: %v, type: %T" , v, v) } }
結果
str[i] value: 65, type: uint8 v value: 65, type: int32
値はどちらも65
しかし型は相違。インデックスアクセスの場合はuint8
, vの場合はint32
実はこれらはbyte
とrune
のエイリアスになっていて、
var x rune = int32(1) var y byte = uint8(1)
この様に書いてもコンパイルエラーにならない。
''
シングルクオートで囲った文字列もrune型として出力
'A' // 65
rangeの値と一緒。どちらもint32
の65を示す
func main() { str := "A" for _, v := range str { if v == 'A' {} // true } }
逆に言うと、int32(65)
をstringでcastするとA
という文字列を取得できる
fmt.Println(string(int32(65))) // A
個人的には結構衝撃的だった
アルファベットを出力する問題
runeとstirngを使った良い例題
英大文字のみからなる文字列 S があります。また、整数 N が与えられます。 S の各文字を、アルファベット順で N 個後の文字に置き換えた文字列を出力してください。 ただしアルファベット順で Z の 1 個後の文字は A とみなします。
直感的にとくと
str := "ABCDEFGHIJKLMNOPQRSTUVWXYZ" m := map[string]int{} for i, v := range str { m[string(v)] = i } var ans string for _, v := range s { i := m[string(v)] target := (i+n) % 26 ans += string(str[target]) } fmt.Println(ans)
値とindexを反転させたmapを作って、各値に対応したindexにnを足した値をSから求める
しかしruneを使えばもっとシンプルに解ける
func main() { scanner := makeScanner(16384) n := eGetInt(scanner) s := eGetLine(scanner) rs := make([]byte, len(s)) alpha := "ABCDEFGHIJKLMNOPQRSTUVWXYZ" for i, c := range s { order := c - 'A' slide := (int(order) + n) % 26 rs[i] = alpha[slide] } fmt.Println(string(rs)) }
アルファベットのruneは連番になっている為、対象文字列をrangeで回して値-Aのrune値
を算出すれば、それがアルファベットの何番目の文字かint32
型で取得できる。
この時取得した値にNを足し、26で割ったあまりが欲しいアルファベットのインデックス。alpha[index番号]
で得られる値はint32
ではなくuint8
なのでbyte配列に結果を代入し最後にキャストする