PHPあがりでGo言語のint→stringキャスト
仕事で使う可能性が出てきたので最近Go言語を勉強してます。
サーバーサイドで高速な処理が期待できる言語だそうですが、ゲーム用のライブラリが出ていたりするなど
(本来の用途とは違うだろうけど)フロントサイドのプログラムもできるみたいです。
さて、表題の内容について。
今までの仕事でjavascriptやphpを多く使ってきたこともあり、Go言語のような静的型付け言語は結構久々なのです。
phpは動的型付け言語ですがAJAXとかでjavascriptにJSON形式で値を返して
javascript側でJSON解析して計算し直すみたいな処理をしようとした時、
// json {"val1": 8, "val2": 8} let r = json.val1 + json.val2; // 文字結合で88にするつもりが加算演算で16になる
文字列結合と加算が同じ符号であるため、意図しない結果になったりします。
phpだと文字列結合と加算は別々の符号なので問題ないですが・・・
こういう時、phpかjavascriptで明示的に型を指定する必要があります。
例えばphpだと
<?php $i = 8; $val1 = (string)$i; // $val1に文字列の8を代入
こんな書き方で数値型の$iを文字列型にキャストしてくれます。
こんなノリをGo言語でやろうとするとうまくいかなかったり・・・
package main import ( "fmt" "strconv" ) func main() { str1 := "6" str2 := "2" var val1, val2, res int val1, _ = strconv.Atoi(str1) val2, _ = strconv.Atoi(str2) res = val1 + val2 str3 := string(res) fmt.Println(res) // 8を出力 fmt.Printf("%T\n", res) // int を出力 fmt.Println(str3) // 空欄になっちゃう(エラーにならない) fmt.Printf("%T\n", str3) // string を出力 fmt.Println(strconv.Itoa(res)) // 8を出力 fmt.Printf("%T\n", strconv.Itoa(res)) // string を出力 fmt.Println(len(str3)) // 1 を出力 var str4 string fmt.Println(len(str4)) // 0 を出力 }
Go言語にもphpに似たような書き方で 型名(変数) という書き方でキャストする方法があります。
とはいえ基本的には int型 / int型 の計算結果をfloat型にするなど、上位型へのキャストに使うものです。
文字列型のstringからは根本的に内容が違うせいか、数字オンリーの内容でも int(string) のキャストはエラーになります。
なので標準ライブラリのstrconvを使ってAtoiで数字オンリーの文字列をint型に変換しています。
逆に string(int) のキャストの場合はエラーが出ません。
しかし、str3 にそのキャストした内容を入れて表示してみましたが、結果には何も表示されません。
strconv.Itoaの方法は想定通りの変換です。
じゃぁ string(res) で戻ってくる値には何が入っているのでしょう?
str4 のように宣言して何もしてないものはlen()で調べても0が戻ってくるので
何も入っていないというわけではなさそうです。
ちょっと計算式を変えてみましょう。
package main import ( "fmt" "strconv" ) func main() { str1 := "6" str2 := "8" var val1, val2, res int val1, _ = strconv.Atoi(str1) val2, _ = strconv.Atoi(str2) res = val1 * val2 // 6*8に変更 str3 := string(res) fmt.Println(res) // 48を出力 fmt.Println(str3) // 0を出力 fmt.Println(len(str3)) // 1 を出力 }
str3自体は0が出力され、len()では1が戻ってきました。
48と0って完全に違う数値じゃん、と思ったのですが、この組み合わせは無関係ではございませんでした・・・
ASCIIコード表によるとコード48には数字の0が対応しています。
つまり string(int) で変換される中身にはコード数値が入り、 fmt.Println() でコードを解析して文字表示してるってことですね。
8がただの空欄になってしまったのはたまたま制御文字(バックスペース)だったので何もありませんでしたが、
10を入れたら制御文字(改行)となり、 fmt.Println() の改行も含めて2行の空欄ができました。
まとめ:int→stringキャストには大人しく strconv.Itoa(int) を使用する
おまけ:fmt.Sprint(変数) を使うと汎用的にstring変換できる