「PerlではこうだけどGolangだとこう書く」のリストです。
これまでPerlを使ってきて、Golangに入門した方向け。すごくニッチです。
スクリプトとコンパイル言語、動的型付けと静的型付けと全く違う言語であり本来比較にならないかと思います。
しかし基礎構文レベルの細かいことでPerlだとこうだけどGolangだとどうやるんだろ?なんて調べることが多く、自分の勉強がてらまとめてみました。
公式リファレンス
手元確認バージョン
- Perl v5.16.3
- Golang 1.11.1 (Playground)
表の項目は細かい方に合わせています。数値と文字列で比較演算子が異なるPerlや、データ型が多いGolangなど。
##コメント
意味 | Perl | Golang |
---|---|---|
単行 | # コメントですよ |
// コメントかな? |
複数行 |
=pod ドキュメントなんかで 使います =cut
|
/* こっちのが みなれてるかも */
|
算術演算子
意味 | Perl | Golang |
---|---|---|
足す | $a + $b |
a + b |
引く | $a - $b |
a - b |
掛ける | $a * $b |
a * b |
割る | $a / $b |
a / b |
余りを求める | $a % $b |
a % b |
インクリメント | $a++ |
a++ |
デクリメント | $a-- |
a-- |
文字列結合 | $a . $b |
a + b |
ほぼ一緒。 |
比較演算子
意味 | Perl | Golang |
---|---|---|
等価 数値 | $a == $b |
a == b |
等価 文字列 | $a eq $b |
a == b |
不等価 数値 | $a != $b |
a != b |
不等価 文字列 | $a ne $b |
a != b |
小なり | $a < $b |
a < b |
以下 | $a <= $b |
a <= b |
大なり | $a > $b |
a > b |
以上 | $a >= $b |
a >= b |
データ型
意味 | Perl | Golang |
---|---|---|
真偽値 | 真=1、偽=0 #perlに真偽値は無い |
真=true、偽=false |
整数 符号なし8bit | my $a = 255 |
var a uint8 = 255 var a byte = 'A' //65
|
整数 符号なし16bit | my $a = 65535 |
var a uint16 = 65535 |
整数 符号なし32bit | my $a = 4294967295 |
var a uint32 = 4294967295 |
整数 符号なし64bit |
use bigint; my $a = 18446744073709551615
|
var a uint64 = 18446744073709551615 |
整数 符号あり8bit | my $a = -128 |
var a int8 = -128 |
整数 符号あり16bit | my $a = -32768 |
var a int16 = -32768 |
整数 符号あり32bit | my $a = -2147483648 |
var a int32 = -2147483648 var a rune = 'あ' //12354
|
整数 符号あり64bit |
use bigint; my $a = -9223372036854775808
|
var a int64 = -9223372036854775808 |
浮動少数 32bit | my $a = 3.14 |
var a float32 = 3.14 |
浮動少数 64bit | my $a = 0.000314159265358979 |
var 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} |
関数 |
my $a = sub { my ($in) = @_; print $in }; &$a('hoge');
|
var a func(string) = func(in string) { fmt.Print(in) } a("hoge") // func(string)型の変数 |
- Perlの数値はおおよそ15桁までで、限界値はOSのライブラリに準じるとの事。それ以上はbigintモジュールを入れます。
- Golangの配列は値で、スライスは配列へのポインタ(+サイズなどの情報を持つ構造体)です。配列はメモリ使用効率に優れる点で、スライスと使い分けされます。
- Golangのbyteとruneは数値型のエイリアスですが慣例的に文字コード(Perlで言うord結果)として使われ、例えば'A'で65が、'あ'で12354が入力されます。文字列として扱うには後述の型変換が必要です。
- 後半Golangの宣言がやたら長いですが、実際はvarを省略したスコープ限定の型推論による代入(:=)を使うことが多いです。
文字列フォーマット
意味 | Perl | Golang |
---|---|---|
型 | - |
%T |
文字 | %s |
%s |
文字 スペース埋め | %2s |
%2s |
2進数 | %b |
%b |
8進数 | %o |
%o |
10進数 | %d |
%d |
10進数 少数 | %f |
%f |
10進数 0埋め | %02d |
%02d |
16進数 小文字 | %x |
%x |
16進数 大文字 | %X |
%X |
ポインタアドレス | %p |
%p |
元がCなので、一緒ですね。 |
printf '%02d', 1;
> 01
import "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 = \$b # ""でアドレス取得 |
var a *int = &b // "&"でアドレス取得 |
配列のアドレス | my $a = \@b |
//bはスライスvar a []int = b //bは配列 var a *[2]int = &b
|
連想配列のアドレス | my $a = \%b |
var a map[string]int = b |
スカラ変数のデリファレンス | print $$a |
fmt.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, c
Golang
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("%s=%x, ", string(v), v)
}
> あ=3042, い=3044, う=3046, え=3048, お=304a,
// 文字列をrangeで回した時点でrune(uint8)として扱われている
// 文字単位で表示したい場合、逆にstring(v)でキャストが必要
// Perlだと%sで暗黙にstrに変換されますが、goだと型エラーで落ちます。
// コード→文字
d := 65
fmt.Print(string(d))
> A
f := 0x3042
fmt.Print(string(f))
> あ
全然足りない気がするけど、とりあえずここまで。