- 投稿日:2019-02-03T11:46:55+09:00
PerlとGolangの対応表っぽいもの
「PerlではこうだけどGolangだとこう書く」のリストです。
これまでPerlを使ってきて、Golangに入門した方向け。すごくニッチです。スクリプトとコンパイル言語、動的型付けと静的型付けと全く違う言語であり本来比較にならないかと思います。
しかし基礎構文レベルの細かいことでPerlだとこうだけどGolangだとどうやるんだろ?なんて調べることが多く、自分の勉強がてらまとめてみました。公式リファレンス
手元確認バージョン
- Perl v5.16.3
- Golang 1.11.1 (Playground)
表の項目は細かい方に合わせています。数値と文字列で比較演算子が異なるPerlや、データ型が多いGolangなど。
コメント
意味 Perl Golang 単行 # コメントですよ// コメントかな?複数行 =podドキュメントなんかで使います=cut/*こっちのがみなれてるかも*/算術演算子
意味 Perl Golang 足す $a + $ba + b引く $a - $ba - b掛ける $a * $ba * b割る $a / $ba / b余りを求める $a % $ba % bインクリメント $a++a++デクリメント $a--a--文字列結合 $a . $ba + bほぼ一緒。
比較演算子
意味 Perl Golang 等価 数値 $a == $ba == b等価 文字列 $a eq $ba == b不等価 数値 $a != $ba != b不等価 文字列 $a ne $ba != b小なり $a < $ba < b以下 $a <= $ba <= b大なり $a > $ba > b以上 $a >= $ba >= bデータ型
意味 Perl Golang 真偽値 真=1、偽=0
#perlに真偽値は無い真=true、偽=false 整数 符号なし8bit my $a = 255var a uint8 = 255var a byte = 'A' //65整数 符号なし16bit my $a = 65535var a uint16 = 65535整数 符号なし32bit my $a = 4294967295var a uint32 = 4294967295整数 符号なし64bit use bigint;my $a = 18446744073709551615var a uint64 = 18446744073709551615整数 符号あり8bit my $a = -128var a int8 = -128整数 符号あり16bit my $a = -32768var a int16 = -32768整数 符号あり32bit my $a = -2147483648var a int32 = -2147483648var a rune = 'あ' //12354整数 符号あり64bit use bigint;my $a = -9223372036854775808var a int64 = -9223372036854775808浮動少数 32bit my $a = 3.14var a float32 = 3.14浮動少数 64bit my $a = 0.000314159265358979var a float64 = 0.000314159265358979文字列 my $a = "hoge"var a string = "hoge"配列 my @a = (1, 2)var a [2]int = [2]int{1, 2}
//配列は桁固定スライス my @a = (1, 2)var a []int = []int{1, 2}
//スライスは可変ハッシュ/マップ my %a = ("hoge" => 1, "fuga" => 2)var a map[string]int = map[string]int{"hoge": 1, "fuga": 2}
- Perlの数値はおおよそ15桁までで、限界値はOSのライブラリに準じるとの事。それ以上はbigintモジュールを入れます。
- Golangの配列は値で、スライスは配列へのポインタ(+サイズなどの情報を持つ構造体)です。配列はメモリ使用効率に優れる点で、スライスと使い分けされます。
- Golangのbyteとruneは数値型のエイリアスですが慣例的に文字コード(Perlで言うord結果)として使われ、例えば'A'で65が、'あ'で12354が入力されます。文字列として扱うには後述の型変換が必要です。
- 後半Golangの宣言がやたら長いですが、実際はvarを省略したスコープ限定の型推論による代入(:=)を使うことが多いです。
文字列フォーマット
意味 Perl Golang 型 -%T文字 %s%s文字 スペース埋め %2s%2s2進数 %b%b8進数 %o%o10進数 %d%d10進数 少数 %f%f10進数 0埋め %02d%02d16進数 小文字 %x%x16進数 大文字 %X%Xポインタアドレス %p%p元がCなので、一緒ですね。
printf '%02d', 1; > 01import "fmt" fmt.Printf("%02d", 1) > 01ヒアドキュメント(複数行の文字列)
Perl
my $a = <<__QUERY; SELECT hoge FROM hage; __QUERY任意の識別子から識別子まで。(上記例は"__QUERY")
Golang
a := `SELECT hoge FROM hage;`バッククォート(`)で囲む。
リファレンス/ポインタ
意味 Perl Golang 無名のスカラ変数のアドレス my $a = \'hoge'my $a = \1-無名の配列のアドレス my $a = [1, 2]//スライス = 配列のポインタ var a []int = []int{1, 2}無名のハッシュのアドレス my $a = {hoge => 1, fuga => 2}//マップは参照型 var a map[string]int = map[string]int{"hoge": 1, "fuga": 2}無名の関数のアドレス my $a = sub {my ($in) = @_; print $in};&$a('hoge');var a func(string) = func(in string) {fmt.Print(in)}a("hoge")スカラ変数のアドレス my $a = \$b
# "\"でアドレス取得var a *int = &b
// "&"でアドレス取得配列のアドレス my $a = \@b//bはスライス var a []int = b
//bは配列var a *[2]int = &bハッシュ/マップのアドレス my $a = \%bvar a map[string]int = bスカラ変数のデリファレンス print $$afmt.Print(*a)配列のデリファレンス print $$a[0]print $a->[0]
#どちらでも良いfmt.Print(a[0])
//配列のポインタはデリファレンスの必要なし
- Golangのスライスとマップはもともと参照型です。interfaceという多態性の為の仕組みがあり、Print時にStringerインターフェイスが実装されていれば実行されます。なのでPerlのように、printしたらアドレスが見れるわけではないです。
- Golangの配列のポインタはスライスかと思ったんですが、あくまで配列のポインタのようです。(配列は固定サイズなのでappendするとエラーになる)
制御構造
条件分岐 if
Perl
# if文 if ($a == 0) { print "0だよ"; } elsif ($a == 1) { print "1だよ"; } else { print "なんだこれ"; } # 三項演算子 print ($a == 0) ? "0だよ" : "なんだこれ";Golang
if a == 0 { fmt.Print("0だよ") } else if a == 1 { fmt.Print("1だよ") } else { fmt.Print("なんだこれ") } // スコープ限定の変数定義 if err := SelectData(); err != nil { fmt.Print("あかん") }
- Golangは括弧が不要です。また、スコープ限定の変数が使えます。
- Golangに三項演算子はありません。
条件分岐 switch
Perl
given ($a) { when ($_ == 1) { print "1だよ"; } default { print "なんだこれ"; } }
- Perlには元々switchはありません。
新機能のgivenは「実験的機能」とされています。私は一度も使ったことがありません。Golang
// aを判定 switch a { case 1: fmt.Print("1だよ") default: fmt.Print("なんだこれ") } // 各条件内で判定 switch { case a == 1: fmt.Print("1だよ") default: fmt.Print("なんだこれ") }
- Golangのswitchはデフォルトでbreakします。
逆に以降の条件も判定したいときは、fallthroughと書きます。
また、いわゆるswitch trueな使い方が正式に実装されています。ループ for
Perl
for (my $i=0; $i<$a; $i++) { print "$iです"; }Golang
for i:=0; i<a; i++ { fmt.Printf("%dです", i) }特に言うことなし。
ループ while
Perl
# 条件に合う限りループ while($a > 1) { print "やばいよループしてますよー"; $a--; } # 無限ループ while(1) { print "∞"; }Golang
// 条件に合う限りループ for ;i<a; { fmt.Printf("%dです", i) } // 無限ループ for { fmt.Print("∞") }
- Golangのループの制御構造は全てforで書きます。
- Golangのforは「初期化; 条件判定; 後処理」の全てが任意に省略できます。
条件判定を省略すれば無限ループになります。イテレータ 配列
Perl
@values = ("a", "b", "c"); foreach my $v (@values) { print $v; } > a, b, cGolang
values := []string{"a", "b", "c"} for i, v := range values { fmt.Printf("%d->%s, ", i, v) } > 0->a, 1->b, 2->c,イテレータ ハッシュ/マップ
Perl
%hash = (a=>1, b=>2, c=>3); foreach my $k (keys %hash) { print "$k\->$hash{$k}, "; } > c->3, a->1, b->2, # ハッシュのキー順序は不定Golang
values := map[string]int{"a": 1, "b": 2, "c": 3} for i, v := range values { fmt.Printf("%s->%d, ", i, v) } > a->1, b->2, c->3, // マップのキー順序も不定型変換
Perl
Perlの場合、スカラ値は強いて言えば文字列か数値かの違いしかありません。# 文字列を示す「"」で囲っても、数値計算できる my $a = "3.14"; print $a * 3; > 9.42 # JSONに渡す時などにたまに使うint my $int = int($str); # 「"」で囲めば文字列扱いになる my $str = "$int";Golang
数値型については、型(値)で変換可能です。a := 1.15 fmt.Printf("%T, %d", int(a), int(a)) > int, 1 b := int(a) fmt.Printf("%T, %f", float64(b), float64(b)) > float64, 1.000000文字列⇔数値はstrconvパッケージを使います。
https://golang.org/pkg/strconv/import "strconv" // 文字列→数値 i, err := strconv.Atoi("-42") // 数値→文字列 s := strconv.Itoa(128)後述しますが以下は数値がアスキーコードと見なされてしまい、
Perlで言うchrの挙動になってしまいますので
「数値をそのまま文字列として表示したい」場合には使えません。i := 65 fmt.Println(string(i)) > A文字⇔アスキーコード変換
Perl
# 文字→コード print ord('A'); > 65 # コード→文字 print chr(65); > A print chr(0x3042); > あGolang
Golangのここが私にとっては特殊(初見)でした。
byteとruneという数値型のエイリアスがあり、文字をシングルクォート「'」で囲むとbyteまたはruneとして、ダブルクォート「"」で囲むと文字列として認識されます。
個人的に最初にここでちょっと詰まり、こういうまとめを作ろうと思ったきっかけでもあります。// この場合byte型 a := 'A' fmt.Print(a) > 65 // この場合string型 b := "B" fmt.Print(b) > B // stringは内部的にはbyte(rune)の配列 fmt.Print(b[0]) > 66 // 文字→コード c := "あいうえお" for _, v := range c { fmt.Printf("%x,", v) } > 3042,3044,3046,3048,304a, // コード→文字 d := 65 fmt.Print(string(d)) > A f := 0x3042 fmt.Print(string(f)) > あ全然足りない気がするけど、とりあえずここまで。