新世代の並列処理言語Google Goをひもとく

第5回 構造体の便利な用途、インターフェイス入門

赤坂 けい
チームWordProgress

2010/3/10

型の異なるオブジェクトの連結

 インターフェイスの簡単な例題として、任意のオブジェクトを「連結(単純につなげる)」させることにチャレンジしてみよう。

 はじめに、準備運動代わりに、静的型言語であるGoでは、型の異なるオブジェクトは、連結・加算できないことを確かめておきたい。

 なお、このままexam5-3.goをコンパイルするとエラーが表示される。

●exam5-3.go
package main

func main() {
    println("a" +"b");
    println("a" +1);
    println("a" +1.2);
}
●実行結果
D:\go-win\mysrc\duck>8g exam5-3.go
exam5-3.go:5: invalid operation: "a" + 1 (type string + int)
exam5-3.go:6: invalid operation: "a" + 1.2 (type string + float)

 Goでは、ほかの多くの言語と同様に、加算記号(+)を用いて、文字列と文字列とを連結できるが、文字列と数値を直接連結させようとすると、コンパイルエラーとなる。

 文字列と数値を連結する場合には、strconvパッケージのItoa関数(整数->文字列)、Ftoa関数(実数->文字列)を用いる(これらの関数名は、Cプログラマにはおなじみだろう)。

 ついでに、整数と実数を足し合わせる演算はコンパイルエラーとならないことも確認しておく。

●exam5-4.go
package main

func main() {
    println(1 +3);
    println(1 +3.0);
    println(1.2 +3);
}
●実行結果
D:\go-win\mysrc\duck>.\8.exe
4
+4.000000e+000
+4.200000e+000

初めてのインターフェイス・プログラム

 これから、インターフェイスの例題として、文字列へのコンバート関数(strconv.Itoa、strconv.Ftoa)を隠蔽したメソッドStrの作成に挑戦してみたい(このサンプルプログラムはあくまで例題であり、実用性には欠ける)。

 Goのインターフェイス宣言は以下のように行う。

type インターフェイス型名 interface { 実装すべきメソッドを列挙 }

 こうして宣言されたGoのインターフェイスは「型(type)」であり、関数の引数などとすることができる。以下のサンプルプログラムで確かめておこう。

●exam5-5.go
package main
import ("fmt"; "strconv")

    //Strメソッドを持つことを条件とするtoStringインターフェイスを定義
    type toString interface { Str() string }
    //toStringインターフェイスを引数に取る関数connectの定義
    func connect (x toString, y toString) string{ return x.Str()+y.Str()}

    //toStringインターフェイスを満たす2つの型myIntとmyFloatを定義
    type myInt int
    func (this myInt) get() int { return int(this) } 
    func (this *myInt) Str() string { return strconv.Itoa(this.get()) } 
    type myFloat float
    func (this myFloat) get() float { return float(this) } 
    func (this *myFloat) Str() string { return fmt.Sprintf("%v",this.get()) } 

    func connectTest(x toString, y toString) {
        fmt.Printf("%sと%sを連結してみます : %s\n",x.Str(),y.Str(),connect(x,y))
    }

func main() {
    var v myInt = 3;
    var f myFloat =1.2;
    connectTest(&v,&f);
    connectTest(&f,&v);
}
●実行結果
D:\go-win\mysrc\duck>.\8.exe
3と1.2を連結してみます : 31.2
1.2と3を連結してみます : 1.23

 まず、冒頭部に注目してほしい。

type toString interface { Str() string }

という形で定義されたtoStringインターフェイスが、直後で定義されている関数connectの引数となっている。

func connect (x toString, y toString) string{ return x.Str()+y.Str()}

toStringインターフェイスであるxとyは、ともにメソッドStr( )を持つであろうため(この時点で、toStringインターフェイスを満たす型は存在しないにも関わらず)、関数connectはコンパイルを通る。

 次の部分では、このtoStringインターフェイスを満たす2つの型myIntとmyFloatを定義している。myIntの実体はint、myFloatの実体はfloatであるが、ともにStr( )メソッドを持つ点で、int、floatとそれぞれ異なる。

 そのため、myIntとint、myFloatとfloatはそれぞれ別物であり、キャスト(型変換)が必要とされる。それぞれのget( )メソッド内のint(this)、float(this)の部分がキャストである。

 これらは、あらかじめ定義したconnect関数の引数とすることができる。関数が呼び出されると、それぞれのStr( )メソッドが呼び出され、両者を結合した文字列が返される。

 数値から文字列への変換方法は複数ある。ここでは、myIntから文字列への変換にはstrconv.Itoa関数を、myFloatから文字列への変換にはfmt.Sprintf関数の"%v"フォーマット(文字列へとよしなに変換してくれるオプション)を用いている。実行結果そのものは、特に注意する点はないだろう。

 プログラムを追いかけてみれば分かるように、myIntとmyFloatは引数として交換可能である。

 ここでのポイントは、toStringインターフェイスを定義した後に、型myIntとmyFloatを定義していることである。これは、大規模なプログラムを作成する際に、事前にインターフェイスをしっかりと定義しておいて、具体的な型の振る舞いはその後に作成することが可能となることを意味している(例えば、当初はモックアップメソッドのみを作成し、実際のメソッドは事後作成する)。

 今回は、Goのインターフェイスを体験した。今回のプログラムだけでは、Goのインターフェイスのどのあたりが便利なのか、ピンとこなかった人が多いのではと思う。次回は、インターフェイスの補充をするとともに、Goの基本機能でまだ触れていないところ(mapなど)を解説していきたいと思う。

next
2/2

Index
構造体の便利な用途、インターフェイス入門
  Page1
Goのインターフェイスの特徴
構造体の便利な定義とダックタイピング
   Page2
オブジェクトをつなげる例題
初めてのインターフェイス・プログラム
index 新世代の並列処理言語Google Goをひもとく

 Coding Edgeお勧め記事
いまさらアルゴリズムを学ぶ意味
コーディングに役立つ! アルゴリズムの基本(1)
 コンピュータに「3の倍数と3の付く数字」を判断させるにはどうしたらいいか。発想力を鍛えよう
Zope 3の魅力に迫る
Zope 3とは何ぞや?(1)
 Pythonで書かれたWebアプリケーションフレームワーク「Zope 3」。ほかのソフトウェアとは一体何が違っているのか?
貧弱環境プログラミングのススメ
柴田 淳のコーディング天国
 高性能なIT機器に囲まれた環境でコンピュータの動作原理に触れることは可能だろうか。貧弱なPC上にビットマップの直線をどうやって引く?
Haskellプログラミングの楽しみ方
のんびりHaskell(1)
 関数型言語に分類されるHaskell。C言語などの手続き型言語とまったく異なるプログラミングの世界に踏み出してみよう
ちょっと変わったLisp入門
Gaucheでメタプログラミング(1)
 Lispの一種であるScheme。いくつかある処理系の中でも気軽にスクリプトを書けるGaucheでLispの世界を体験してみよう
  Coding Edgeフォーラムフィード  2.01.00.91


Coding Edge フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

>

Coding Edge 記事ランキング

本日 月間