Perlの配列をn個ずつの配列に分割する

splice して push する。破壊的なので注意。

^o^ > perl chunk.pl
array:0123456789
chunk:012
chunk:345
chunk:678
chunk:9
array:

インターフェイス

インターフェイスとは、異なる型の構造体を同じ型として扱うための抽象型のようなものだ。Java のインターフェイスと同様らしいけど Java のことはよく知らない。インターフェイスにはメソッドの型だけが定義されていて、そのメソッドすべてを実装した構造体はインターフェイスの型として扱えるようになる。

次の例では、インターフェイス Point を定義している。Point 型は distance0 というメソッドを持っている。Point2dPoint3d というのが具体的な構造体で、そのどちらもが distance0 メソッドを実装しているので、Point 型として1つのスライスに格納されている。

^o^ > go run interface.go
0
14.142135623730951
0
17.320508075688775
31.462643699419726

構造体の埋め込み

Go はオブジェクト指向言語ではないけど、「構造体の埋め込み」という機能によって、似たようなことができる。
例を見てみよう。構造体 Bar にはフィールド foo として構造体 Foo が指定されている。これは単に、フィールドが構造体なだけであって、埋め込みとは言わない。一方、構造体 Baz にはフィールド名を省略して Foo が指定されている。これを匿名フィールドと言って、Baz には Foo のフィールドやメソッドが引き継がれる。これを構造体の埋め込みという。

変数 y は構造体 Bar で、Foo を埋め込んでいないので、y.printA() のようなメソッド呼び出しはできない。一方、変数 zFoo を埋め込んでいるので、z.printA() のように Foo のメソッドを呼び出すことができる。

o^ > go run struct_embed.go
a = 1
b = 2
a = 10
b = 20
c = 30
a = 100
Baz:b = 200
c = 300

複数の構造体を埋め込むこともできる。ただし、埋め込んだ構造体同士でフィールド名やメソッド名が重複すると、やや面倒になる。次の例では、構造体 Baz には FooBar が埋め込んであるけど、フィールド a とメソッド printA が重複している。こういう時は構造体名を明示して呼び出さなければならない。

^o^ > go run struct_embed2.go
0
20
30

連結リスト

連結リストとは、値を保持するセルが数珠つなぎになった構造、つまり Scheme のリストと同じ構造だ。
今日は構造体やメソッドの練習として、連結リストのプログラムを写経してみる。
書き忘れていたけど、Go の一連の勉強は↓このページに沿ってやっている。

 cf. お気楽 Go 言語プログラミング入門 – M.Hiroi’s Home Page

連結リストがあるのはこのページの中ほど。

 cf. お気楽 Go 言語プログラミング入門 構造体 – M.Hiroi’s Home Page

それじゃ、行ってみよう。

それほど難しくはない。ちょっと注意が必要なのは、List 構造体の top フィールドに入っている Cell 構造体はダミーで、その次の Cell が0番目の Cell になってるってところかな。
実行結果:

^o^ > go run linkedlist.go
true
true
true
true
0 1 2 3
0 true
1 true
2 true
3 true
0 false
1 2 3
2 3
3

うまくいった。

メソッド

メソッドは、構造体(の型)と結びつけられた関数だ。Go はオブジェクト指向プログラミング言語ではないけど、このメソッドや構造体の埋め込み(これについては後で書くつもり)によって、オブジェクト指向的なプログラミングができるようになっている。
例を挙げよう。
前のエントリでは平面上の点を表す Point 構造体と、2点間の距離を求める distance 関数を作った。ここでもう一つ、3次元空間の点を表す Point3d 構造体を作る。この2点間の距離を求める関数を考えたとき、distance という名前は使えない。すでに名前を使ってしまっているからだ。
ところが、これらをそれぞれの構造体のメソッドにすれば、両方とも distance という名前にできる。
メソッドの一般亭な定義は次の通り。

ここで、関数名の前のカッコの中にある仮引数をレシーバと言い、このメソッドはレシーバの型と結びつけられる。これで、PointPoint3d の両方の構造体に、同じ distance という名前のメソッドが定義できるわけだ。
実際に書いてみよう。

^o^ > go run method.go
14.142135623730951
17.320508075688775

構造体

構造体は、既存の型を組み合わせて新しい型を作る機能だ。とりあえずは C の構造体を同じようなものだと考えればいい。
構造体の定義は type キーワードを使って次のようにする。

構造体を構成するデータは、フィールドと呼ばれる。上のようにフィールドとその型を列記すればいい。

構造体の初期化は、構造体名{フィールド1, フィールド2, …} のようにフィールドを順に並べるほか、フィールド名とそのデータを組みにして渡す方法がある。後者では定義と順番が異なってもいい。また、フィールドへのアクセスは . 演算子を使う。例を示そう。

ここでは Point という名前の構造体を使っている。構造体の初期化は、main 関数の冒頭で行っている。変数 pq は上に書いたように初期化している。変数 o は初期化していないので、自動的にゼロ値に初期化される。
distance 関数の中で、構造体のフィールドにアクセスしている。

^o^ > go run struct.go
{0 0}
{10 10}
{100 200}
0
0
10
10
100
200
14.142135623730951
223.60679774997897
210.23796041628637

次は、構造体のポインタの例を示そう。構造体の場合も普通の型のように、アドレスを取得するには & を、値にアクセスするには * を使えばいい。ただし、フィールドにアクセスするときは、C のように -> を使うのではなく、. を使う。このへんは構造体の変数なのかポインタなのかを気にしなくていいので楽だな。

^o^ > go run struct2.go
&{0 0}
&{10 10}
&{100 200}
0
0
10
10
100
200
14.142135623730951
223.60679774997897
210.23796041628637

構造体をポインタとして使うときは、初期化用の関数を使うのが通例のようだ。次の例では、newPoint 関数がそれにあたる。この関数は、ポインタのフィールドになる値を引数にとって、構造体のポインタを返す。

^o^ > go run struct3.go
&{0 0}
&{10 10}
0
0
10
10
14.142135623730951

最後に、構造体をスライスに格納する例を示して今日は終わりにしよう。構造体だからと言って何も特別なことはない。

^o^ > go run struct_slice.go
[{0 0} {10 10} {100 100}]
[       ]
[0xc042008270 0xc042008280 0xc042008290 0xc0420082a0 0xc0420082b0 0xc0420082c0 0xc0420082d0 0xc0420082e0]
&{0 0}
&{1 1}
&{2 2}
&{3 3}
&{4 4}
&{5 5}
&{6 6}
&{7 7}

メモリの動的割り当て

new 関数は、動的にメモリを割り当ててそのアドレス、つまりポインタを返す。

例を示そう。

^o^ > go run dynamic_alloc.go
0xc042008210
0
0xc042008218
0
&[0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0]
100
1.2345
[10 0 0 0 0 0 0 80]

本題と関係ないけど、配列(と、たぶんスライスも)を指すポインタから要素へのアクセスは * をつけなくてできるんだな。

ポインタ

Go のポインタは C のポインタに似ている。変数のアドレスを得るためには & を使い、ポインタのさす値を参照するには * を使う。宣言するのに * を使うのも一緒だけど、Go の場合には変数名ではなく型の前につける。

^o^ > go run pointer.go
10
10
100
100
0xc042008210
true

C と違う点はほかにもある。Go のポインタは、整数値の代入や加減算はできないようになっている。配列のアドレスもそうだ。C では配列へのポインタはその配列の先頭要素へのポインタになっていて、各要素にアクセスするにはポインタをインクリメントしたりとかする。Go ではこういうことはできない。配列へのポインタは配列そのものへのポインタであって、配列の要素へのアクセスはできないようだ。もちろん、配列の要素へのポインタは作れる。

^o^ > go run pointer_array.go
&[1 2 3 4]
[1 2 3 4]
1
0xc042002700
1
0xc042002708
2
2
[10 20 3 4]
[10 20 30 40]

以前に、関数の呼び出しは値渡しだと書いた。関数のポインタを渡してやると、ポインタは仮引数にコピーされるけど、そのさしている値は呼び出し元と同じ値だ。つまり、ポインタを使えば参照渡しと同等のことかできる。

^o^ > go run pointer_call.go
10
20
[1 2 3 4]
20
10
[10 20 30 40]

さて、ポインタの基本はこんなところ。

クロージャ

昨日、一昨日のエントリで、関数を引数にとる高階関数を見てきた。今度は関数を返す関数を考えよう。
関数を返すには、return で関数を返してやればいいだけだ。それだけだと芸がないので、もう一ひねりしてみる。Go では、関数を定義した環境の変数を保持することができる。クロージャだ。
例を示そう。

genCounter の中で定義している匿名関数(これが genCounter の返り値になる)は、その外側にある変数 i を覚えている。なので、返り値の関数は呼び出されるごとに i をインクリメントしてから値を返す。

^o^ > go run closure.go
1
2
3

この通り。

mapcarとfilter

高階関数の練習に、mapcarfilter を作ってみた。

まずは mapcar から。

^o^ > go run mapcar.go
[1 2 3 4 5]
[1 4 9 16 25]
[1 8 27 64 125]

つぎは filter

^o^ > go run filter.go
[2 4 6 8]