20190203のPerlに関する記事は1件です。

PerlとGolangの対応表っぽいもの

「PerlではこうだけどGolangだとこう書く」のリストです。
これまでPerlを使ってきて、Golangに入門した方向け。すごくニッチです。

スクリプトとコンパイル言語、動的型付けと静的型付けと全く違う言語であり本来比較にならないかと思います。
しかし基礎構文レベルの細かいことでPerlだとこうだけどGolangだとどうやるんだろ?なんて調べることが多く、自分の勉強がてらまとめてみました。

公式リファレンス

手元確認バージョン

表の項目は細かい方に合わせています。数値と文字列で比較演算子が異なる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}
  • 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 = 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 = \%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("%x,", v)
}
> 3042,3044,3046,3048,304a,

// コード→文字
d := 65
fmt.Print(string(d))
> A

f := 0x3042
fmt.Print(string(f))
> 

全然足りない気がするけど、とりあえずここまで。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む