Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 11093] ファイルの概要

このコミットは、Go言語の標準ライブラリimageパッケージにおいて、image.Tiledという型および関連する関数名をimage.Repeatedにリネームする変更を導入しています。この変更の主な目的は、既存のTiledの実装が「小さな画像を繰り返して大きな画像を構成する」という特定の機能に限定されているため、その実態をより正確に反映する名前に変更することです。これにより、将来的に「タイリング」というより広範な概念(例: Google Mapsのような異なるタイルを組み合わせる、巨大な画像を部分的に表示する)を扱うためのimage.Tiledという名前を温存しています。

このリネームは、gofixツールによって自動的にコードベース全体に適用されるように、gofixの新しい修正ルールも追加されています。

コミット

Author: Nigel Tao nigeltao@golang.org Date: Wed Jan 11 12:35:05 2012 +1100

image: rename image.Tiled to image.Repeated.

What package image currently provides is a larger image consisting
of many copies of a smaller image.

More generally, a tiled image could be a quilt consisting of different
smaller images (like Google Maps), or a technique to view a portion of
enormous images without requiring the whole thing in memory.

This richer construct might not ever belong in the standard library (and
is definitely out of scope for Go 1), but I would like the option for
image.Tiled to be its name.

R=r, rsc
CC=golang-dev
https://golang.org/cl/5530062

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/415f15b66746d8e0cd6f01e89dceed41e617be5f

元コミット内容

image: rename image.Tiled to image.Repeated.

What package image currently provides is a larger image consisting
of many copies of a smaller image.

More generally, a tiled image could be a quilt consisting of different
smaller images (like Google Maps), or a technique to view a portion of
enormous images without requiring the whole thing in memory.

This richer construct might not ever belong in the standard library (and
is definitely out of scope for Go 1), but I would like the option for
image.Tiled to be its name.

R=r, rsc
CC=golang-dev
https://golang.org/cl/5530062

変更の背景

この変更の背景には、Go言語のimageパッケージにおけるAPI設計の意図と、将来的な拡張性への配慮があります。

元々image.Tiledという名前で提供されていた機能は、実際には「単一の小さな画像を無限に繰り返して大きな仮想画像を生成する」というものでした。しかし、「タイリング(tiling)」という言葉は、画像処理の文脈においてより広範な意味を持つことがあります。例えば、Google Mapsのように異なる複数の画像を組み合わせて全体像を形成する「モザイク画像」や、非常に大きな画像をメモリに全て読み込むことなく部分的に表示するための「タイルベースの画像処理」といった概念が含まれます。

コミットメッセージにあるように、現在のimage.Tiledの実装は、これらのよりリッチな「タイリング」の概念とは異なり、単なる「繰り返し」に過ぎません。そのため、API名がその機能の実態と乖離しているという問題がありました。

この乖離を解消し、APIのセマンティクスをより明確にするために、image.Tiledimage.Repeatedにリネームされました。これにより、image.Tiledという名前は、将来的にGoの標準ライブラリでより汎用的なタイリング機能が導入される可能性に備えて、予約された状態になります。Go 1のスコープ外ではあるものの、将来的な拡張性を考慮した、API設計における先見の明を示す変更と言えます。

前提知識の解説

Go言語のimageパッケージ

Go言語の標準ライブラリには、画像処理のためのimageパッケージが含まれています。このパッケージは、様々な画像フォーマット(PNG, JPEGなど)の読み書き、画像の生成、操作、変換といった基本的な機能を提供します。

  • image.Imageインターフェース: imageパッケージの中心となるのはImageインターフェースです。これは、ColorModel() color.ModelBounds() RectangleAt(x, y int) color.Colorという3つのメソッドを定義しており、これにより任意の画像データを抽象的に扱うことができます。
    • ColorModel(): 画像の色の表現方法(例: RGBA、グレースケール)を返します。
    • Bounds(): 画像のピクセル座標における境界(長方形)を返します。
    • At(x, y int): 指定された座標のピクセルの色を返します。
  • image.Pointimage.Rectangle: 画像内の座標や領域を表すための基本的な型です。
  • color.Color: 色を表すインターフェースで、RGBA()メソッドを持ちます。

このコミットで変更されるTiled(変更後はRepeated)は、このimage.Imageインターフェースを実装しており、あたかも無限に広がる画像であるかのように振る舞います。

gofixツール

gofixは、Go言語のソースコードを自動的に修正するためのコマンドラインツールです。Go言語のAPIが変更されたり、言語仕様が更新されたりした場合に、古いコードを新しいAPIや仕様に準拠させるために使用されます。

gofixは、Goのソースコードを抽象構文木(AST: Abstract Syntax Tree)として解析し、定義された「修正ルール(fix rule)」に基づいてASTを変換することでコードを書き換えます。これにより、開発者は手動で大量のコードを修正する手間を省き、APIの変更に迅速に対応できます。

このコミットでは、image.Tiledからimage.RepeatedへのリネームというAPI変更に対応するため、新しいgofixの修正ルールが追加されています。

画像処理における「タイリング」と「繰り返し」

  • 繰り返し (Repeating): 単一の画像を、水平方向および垂直方向に単純に並べて、より大きな(あるいは無限の)画像を生成する手法です。同じパターンが連続して現れるため、テクスチャや背景などに利用されます。このコミットでimage.Repeatedが指すのはこの概念です。
  • タイリング (Tiling): より広範な概念で、複数の異なる画像(タイル)を組み合わせて、より大きな画像を構成する手法を指します。
    • モザイク画像: 異なる内容の小さな画像を並べて、全体として一つの大きな画像を表現する。
    • 巨大画像の表示: Google Mapsのように、非常に大きな画像を小さな領域(タイル)に分割し、必要な部分だけを読み込んで表示することで、メモリ使用量を抑えつつ効率的に画像を扱う手法。
    • テクスチャアトラス: ゲーム開発などで、複数の小さなテクスチャを一枚の大きな画像にまとめておく手法。

image.Tiledという名前は、後者のより複雑で汎用的なタイリングの概念を想起させるため、現在のimageパッケージの実装(単なる繰り返し)とは意味合いが異なっていました。この乖離が、今回のリネームの動機となっています。

技術的詳細

このコミットの技術的詳細は、主に以下の2つの側面から構成されます。

  1. imageパッケージ内のAPI名称変更: src/pkg/image/names.goファイルにおいて、Tiledという名前の型、そのレシーバメソッド、およびコンストラクタ関数がRepeatedに一括して変更されています。これは、APIのセマンティクスをより正確に反映させるための直接的な変更です。

    • type Tiled structtype Repeated struct に変更。
    • func (t *Tiled) のレシーバ変数名が t から r に変更され、型も *Repeated に変更。
    • func NewTiledfunc NewRepeated に変更。
    • 関連するコメントもTiledからRepeatedに更新されています。
  2. gofixツールの修正ルールの追加: このAPI名称変更は、既存のGoコードベースに影響を与えるため、gofixツールが自動的にコードを修正できるように新しいルールが追加されました。

    • src/cmd/gofix/imagetiled.goが新規作成され、image.Tiledimage.Repeatedにリネームするgofixの修正ロジックが実装されています。
    • このファイルでは、GoのAST(抽象構文木)を走査し、image.Tiledという形式のセレクタ式(例: image.Tiled{...}var _ image.Tiled)を見つけると、そのTiledの部分をRepeatedに書き換える処理が行われます。
    • src/cmd/gofix/imagetiled_test.goも新規作成され、このgofixルールが正しく機能するかどうかを検証するためのテストケースが記述されています。テストケースは、入力コード(In)と期待される出力コード(Out)のペアで構成され、image.Tiledimage.Repeatedに変換されることを確認します。
    • src/cmd/gofix/Makefileに、新しく追加されたimagetiled.gogofixのビルド対象に含まれるように変更が加えられています。

このアプローチにより、Go言語のAPI変更がユーザーのコードベースに与える影響を最小限に抑えつつ、スムーズな移行を可能にしています。gofixは、Go言語の進化において重要な役割を果たすツールであり、このようなAPIリネームの自動化はその典型的なユースケースです。

コアとなるコードの変更箇所

このコミットにおけるコアとなるコードの変更箇所は以下のファイルに集中しています。

src/pkg/image/names.go

このファイルは、imageパッケージ内で定義されている様々な画像関連の型やコンストラクタ関数を含んでいます。

--- a/src/pkg/image/names.go
+++ b/src/pkg/image/names.go
@@ -51,25 +51,25 @@ func NewUniform(c color.Color) *Uniform {
 	return &Uniform{c}
 }
 
-// A Tiled is an infinite-sized Image that repeats another Image in both
-// directions. Tiled{i, p}.At(x, y) will equal i.At(x+p.X, y+p.Y) for all
+// Repeated is an infinite-sized Image that repeats another Image in both
+// directions. Repeated{i, p}.At(x, y) will equal i.At(x+p.X, y+p.Y) for all
 // points {x+p.X, y+p.Y} within i\'s Bounds.
-type Tiled struct {
+type Repeated struct {
 	I      Image
 	Offset Point
 }
 
-func (t *Tiled) ColorModel() color.Model {\n-\treturn t.I.ColorModel()\n+func (r *Repeated) ColorModel() color.Model {\n+\treturn r.I.ColorModel()\n }
 
-func (t *Tiled) Bounds() Rectangle { return Rectangle{Point{-1e9, -1e9}, Point{1e9, 1e9}} }\n+func (r *Repeated) Bounds() Rectangle { return Rectangle{Point{-1e9, -1e9}, Point{1e9, 1e9}} }\n 
-func (t *Tiled) At(x, y int) color.Color {\n-\tp := Point{x, y}.Add(t.Offset).Mod(t.I.Bounds())\n-\treturn t.I.At(p.X, p.Y)\n+func (r *Repeated) At(x, y int) color.Color {\n+\tp := Point{x, y}.Add(r.Offset).Mod(r.I.Bounds())\n+\treturn r.I.At(p.X, p.Y)\n }
 
-func NewTiled(i Image, offset Point) *Tiled {\n-\treturn &Tiled{i, offset}\n+func NewRepeated(i Image, offset Point) *Repeated {\n+\treturn &Repeated{i, offset}\n }

src/cmd/gofix/imagetiled.go (新規追加)

このファイルは、gofixツールがimage.Tiledimage.Repeatedに自動修正するためのロジックを実装しています。

// Copyright 2012 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"go/ast"
)

func init() {
	register(imagetiledFix)
}

var imagetiledFix = fix{
	"imagetiled",
	"2012-01-10",
	imagetiled,
	`Rename image.Tiled to image.Repeated.

http://codereview.appspot.com/5530062
`,
}

func imagetiled(f *ast.File) bool {
	if !imports(f, "image") {
		return false
	}

	fixed := false
	walk(f, func(n interface{}) {
		s, ok := n.(*ast.SelectorExpr)
		if !ok || !isTopName(s.X, "image") || s.Sel.String() != "Tiled" {
			return
		}
		s.Sel = &ast.Ident{Name: "Repeated"} // ここがTiledをRepeatedに書き換える核心部分
		fixed = true
	})
	return fixed
}

src/cmd/gofix/imagetiled_test.go (新規追加)

このファイルは、gofiximagetiled修正が正しく機能するかを検証するためのテストケースを含んでいます。

// Copyright 2012 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

func init() {
	addTestCases(imagetiledTests, imagetiled)
}

var imagetiledTests = []testCase{
	{
		Name: "imagetiled.0",
		In: `package main

import (
	"foo"
	"image"
)

var (
	_ foo.Tiled
	_ image.RGBA
	_ image.Tiled // この行が修正対象
)
`,
		Out: `package main

import (
	"foo"
	"image"
)

var (
	_ foo.Tiled
	_ image.RGBA
	_ image.Repeated // この行が修正後
)
`,
	},
}

コアとなるコードの解説

src/pkg/image/names.goの変更

このファイルにおける変更は、imageパッケージの公開APIの名称を直接変更するものです。

  • type Tiled struct から type Repeated struct: Tiledという構造体名がRepeatedに変更されました。これにより、この型が表現する「画像を繰り返す」という機能がより明確になります。
  • レシーバメソッドの変更: func (t *Tiled) のようにTiled型をレシーバとするメソッドも、func (r *Repeated) のようにRepeated型をレシーバとするように変更されました。レシーバ変数名も慣習に従いtからrに変更されています。これらのメソッド(ColorModel, Bounds, At)は、image.Imageインターフェースの実装であり、Repeated型が画像として振る舞うためのものです。
  • コンストラクタ関数の変更: func NewTiledfunc NewRepeated に変更されました。これは、新しいRepeated型のインスタンスを生成するための公開関数です。

これらの変更は、imageパッケージのAPIがその機能とセマンティクスをより正確に表現するように改善されたことを意味します。

src/cmd/gofix/imagetiled.goimagetiled関数

この関数は、gofixツールの中核をなす部分であり、Goのソースコードを解析し、特定のパターンに合致するコードを自動的に書き換えます。

  1. imports(f, "image"): まず、処理対象のファイルf"image"パッケージをインポートしているかどうかを確認します。imageパッケージを使用していないファイルは、この修正の対象外となるため、無駄な処理を避けることができます。
  2. walk(f, func(n interface{}) {...}): walk関数は、GoのAST(抽象構文木)を深さ優先で走査するためのユーティリティです。ASTの各ノードnに対して、無名関数が実行されます。
  3. s, ok := n.(*ast.SelectorExpr): 現在のASTノードn*ast.SelectorExpr型(セレクタ式、例: image.Tiledimage.Tiled全体)であるかをチェックします。
  4. !ok || !isTopName(s.X, "image") || s.Sel.String() != "Tiled":
    • !ok: *ast.SelectorExpr型でなければスキップします。
    • !isTopName(s.X, "image"): セレクタ式の左側(s.X、例: image.Tiledimage部分)が"image"という名前の識別子でなければスキップします。これにより、foo.Tiledのような他のパッケージのTiledという名前には影響を与えません。
    • s.Sel.String() != "Tiled": セレクタ式の右側(s.Sel、例: image.TiledTiled部分)が"Tiled"という文字列でなければスキップします。 これらの条件を全て満たす場合、それはimage.Tiledというパターンに合致するコードであると判断されます。
  5. s.Sel = &ast.Ident{Name: "Repeated"}: ここがこの修正の核心部分です。image.TiledTiledという識別子を、新しいRepeatedという識別子に書き換えます。これにより、ASTが変更され、最終的に新しいコードが生成されます。
  6. fixed = true: 修正が行われたことを示すフラグを立てます。
  7. return fixed: 修正が行われた場合はtrueを返し、gofixツールにファイルが変更されたことを伝えます。

このimagetiled関数は、GoのAST操作の典型的な例であり、コンパイラやコード分析ツール、自動リファクタリングツールなどで広く用いられる技術です。

src/cmd/gofix/imagetiled_test.goのテストケース

このテストファイルは、imagetiled修正が意図通りに動作することを保証します。

  • addTestCases(imagetiledTests, imagetiled): imagetiledTestsというテストケースのスライスをimagetiled関数に関連付けて登録します。
  • testCase構造体: 各テストケースはName(テストケース名)、In(入力となるGoのソースコード)、Outgofix適用後に期待されるGoのソースコード)で構成されます。
  • テストの目的: 提供されたテストケースでは、var _ image.Tiledという行がvar _ image.Repeatedに正しく変換されることを確認しています。これにより、gofixがユーザーのコードベースでimage.Tiledの使用箇所を正確に特定し、image.Repeatedに書き換える能力があることが検証されます。

このようなテストの存在は、自動コード修正ツールの信頼性を高める上で不可欠です。

関連リンク

参考にした情報源リンク

  • Go言語公式ドキュメント: imageパッケージ (https://pkg.go.dev/image)
  • Go言語公式ドキュメント: go/astパッケージ (https://pkg.go.dev/go/ast)
  • Go言語公式ドキュメント: gofixコマンド (Goのバージョンによってドキュメントの場所が異なる場合がありますが、通常はGoのツールに関するセクションに記載されています。)
    • Go 1.xのドキュメント: go help fix または go doc cmd/gofix で詳細を確認できます。