A Tour of Go の Exercise: Images 解答例

はじめに

Go 言語基礎文法最速マスターにて出題されている演習課題「Exercise: Images(イメージ)」の答えに辿り着くまでの手順と解答例の解説を記事にしてみました。

課題

課題の目的は Exercise: Slices 解答例 で作成した画像ジェネレーターを参考にして、データのスライスの代わりに image.Image インタフェースの実装を返すようにすることです。

package main

import "golang.org/x/tour/pic"

type Image struct{}

func main() {
	m := Image{}
	pic.ShowImage(m)
}

解答例

package main

import (
	"golang.org/x/tour/pic"
	"image"
	"image/color"
)

type Image struct {}

func (m *Image) ColorModel() color.Model {
	return color.RGBAModel
}

func (m *Image) Bounds() image.Rectangle {
	return image.Rect(0, 0, 128, 128)
}

func (m *Image) At(x, y int) color.Color {
	v := uint8(x ^ y)
	return color.RGBA{v, v, 255, 255}
}

func main() {
	m := Image{}
	pic.ShowImage(&m)
}

実行結果は下記のようになります。

解説

初めに、課題のソースコードを読み解きます。

ほぼ Exercise: Slices と同じなので差分だけ説明します。

5 行目、type で struct{} 型を Image という名前で 型宣言 していますね。

type Image struct{}

課題の文章より、この Image 型に インタフェースを満たすのに必要なメソッド を実装して pic.ShowImage 関数を呼び出してねとあります。

下記の Image インターフェースのソースコードを見てわかる通り、必要なメソッドとは ColorModel(), Bounds(), At(x, y int) の 3 つのことです。

type Image interface {
	// ColorModel returns the Image's color model.
	ColorModel() color.Model
	// Bounds returns the domain for which At can return non-zero color.
	// The bounds do not necessarily contain the point (0, 0).
	Bounds() Rectangle
	// At returns the color of the pixel at (x, y).
	// At(Bounds().Min.X, Bounds().Min.Y) returns the upper-left pixel of the grid.
	// At(Bounds().Max.X-1, Bounds().Max.Y-1) returns the lower-right one.
	At(x, y int) color.Color
}

7 – 10 行目、main 関数では Image{} 型を変数 m に格納、pic.ShowImage 関数に渡して画像を出力しています。

func main() {
	m := Image{}
	pic.ShowImage(m)
}

さて、実装を進めます。

やることは Image インターフェースの ColorModel(), Bounds(), At(x, y int) を実装することですね、ひとつずつやっていきます。

まずは ColorModel() を実装します。

ColorModel() color.Model

課題の文章より「ColorModel は、color.RGBAModel を返すようにします。」とあるので、下記のように書けば良いだけですね。

func (m *Image) ColorModel() color.Model {
	return color.RGBAModel
}

image/color パッケージのインポートも忘れずに。

import (
	"golang.org/x/tour/pic"
	"image/color"
)

次は Bounds() を実装します。

Bounds() Rectangle

課題の文章より「Bounds は、image.Rect(0, 0, w, h) のようにして image.Rectangle を返すようにします。」とあります。

変数 w, h は出力する画像の width(横幅)と height(高さ)のことです、今回は適当に 128 で設定しました。

func (m *Image) Bounds() image.Rectangle {
	return image.Rect(0, 0, 128, 128)
}

image パッケージのインポートも忘れずに。

import (
	"golang.org/x/tour/pic"
	"image"
	"image/color"
)

次は At(x, y int) を実装します。

At(x, y int) color.Color

課題の文章より「At は、ひとつの色を返します。 生成する画像の色の値 vcolor.RGBA{v, v, 255, 255} を利用して返すようにします。」とあります。

変数 v には前に Exercise: Slices でやったように uint8(intValue) を使うと良いです。

func (m *Image) At(x, y int) color.Color {
	v := uint8((x + y) / 2)
	return color.RGBA{v, v, 255, 255}
}

3 つのメソッドの実装が完了しました、纏めると下記のようになります。

package main

import (
	"golang.org/x/tour/pic"
	"image"
	"image/color"
)

type Image struct {}

func (m *Image) ColorModel() color.Model {
	return color.RGBAModel
}

func (m *Image) Bounds() image.Rectangle {
	return image.Rect(0, 0, 128, 128)
}

func (m *Image) At(x, y int) color.Color {
	v := uint8((x + y) / 2)
	return color.RGBA{v, v, 255, 255}
}

func main() {
	m := Image{}
	pic.ShowImage(&m)
}

実行結果は下記のようになります。

大丈夫だ、問題ない。

以上です。

おわりに

インターフェースの実装の御浚いといった内容の課題でした。