コンテンツにスキップ

Go/メソッドチェイン

出典: フリー教科書『ウィキブックス(Wikibooks)』
< Go

メソッドチェイン

[編集]

Goのメソッドは、メソッドチェイン(method chaining)が可能です。

メソッドチェイン
package main

import "fmt"

// Student 構造体を定義
type Student struct {
	name string
	age  int
}

// PrintName メソッドを定義(ポインタレシーバー)
func (s *Student) PrintName() *Student {
	fmt.Printf("Name: %v\n", s.name)
	return s // メソッドチェインのため、ポインタを返す
}

// PrintAge メソッドを定義(ポインタレシーバー)
func (s *Student) PrintAge() *Student {
	fmt.Printf("Age: %v\n", s.age)
	return s // メソッドチェインのため、ポインタを返す
}

func main() {
	// 学生のリストを定義
	students := [...]Student{
		{name: "joe", age: 17},
		{name: "tom", age: 18},
		{name: "alice", age: 17},
	}

	// 学生ごとにPrintNameとPrintAgeを呼び出し
	// 配列要素を直接ループ
	for _, student := range students {
		student.PrintName().PrintAge() // メソッドチェイン
	}
}
結果
Name: joe
Age: 17
Name: tom
Age: 18
Name: alice
Age: 17

遅延評価を使用するシーケンス

[編集]
lazy.go
package main

import (
	"fmt"
	"strings"
)

// Seq は遅延評価を使用するシーケンスを表す型
type Seq[T any] func(yield func(T) bool)

// 新しいSeqを作成する関数
func NewSeq[T any](elements ...T) Seq[T] {
	return func(yield func(T) bool) {
		for _, el := range elements {
			if !yield(el) {
				break
			}
		}
	}
}

// Push はSeqの末尾に要素を追加
func (seq Seq[T]) Push(element T) Seq[T] {
	return func(yield func(T) bool) {
		seq(func(v T) bool {
			if !yield(v) {
				return false
			}
			return true
		})
	}
}

// Pop はSeqの末尾から要素を削除(シミュレート)
func (seq Seq[T]) Pop() Seq[T] {
	return func(yield func(T) bool) {
		// Pop動作を実装するためにはSeqを一度リストに変換して操作する必要あり
		// ここでは簡略化してます。
		seq(yield) // 戻り値のシミュレーション
	}
}

// Map はSeqの各要素に対して関数を適用
func (seq Seq[T]) Map(fn func(T) T) Seq[T] {
	return func(yield func(T) bool) {
		seq(func(v T) bool {
			return yield(fn(v))
		})
	}
}

// Filter はSeqの各要素を条件でフィルタリング
func (seq Seq[T]) Filter(fn func(T) bool) Seq[T] {
	return func(yield func(T) bool) {
		seq(func(v T) bool {
			if fn(v) {
				return yield(v)
			}
			return true
		})
	}
}

// Reduce はSeqの各要素を累積的に処理
func (seq Seq[T]) Reduce(fn func(T, T) T, initial T) T {
	accumulator := initial
	seq(func(v T) bool {
		accumulator = fn(accumulator, v)
		return true
	})
	return accumulator
}

// Concat は二つのSeqを結合
func (seq1 Seq[T]) Concat(seq2 Seq[T]) Seq[T] {
	return func(yield func(T) bool) {
		seq1(yield)
		seq2(yield)
	}
}

// ForEach はSeqの各要素に対して指定された関数を実行
func (seq Seq[T]) ForEach(fn func(T)) {
	seq(func(v T) bool {
		fn(v)
		return true
	})
}

// ToSlice はSeqをスライスに変換
func ToSlice[T any](seq Seq[T]) []T {
	var result []T
	seq(func(v T) bool {
		result = append(result, v)
		return true
	})
	return result
}

// Stringerインターフェースを実装
func (seq Seq[T]) String() string {
	slice := []string{}
	seq(func(v T) bool {
		slice = append(slice, fmt.Sprintf("%v", any(v)))
		return true
	})
	return fmt.Sprintf("{%s}", strings.Join(slice, ", "))
}

// GoStringerインターフェースを実装
func (seq Seq[T]) GoString() string {
	slice := []string{}
	seq(func(v T) bool {
		slice = append(slice, fmt.Sprintf("%v", any(v)))
		return true
	})
	return fmt.Sprintf("NewSeq(%s)", strings.Join(slice, ", "))
}

func main() {
	// Seqを作成
	seq1 := NewSeq(1, 2, 3)
	seq2 := NewSeq(4, 5)

	// Seqを結合
	seq3 := seq1.Concat(seq2)

	// 結果をToSliceで表示
	fmt.Printf("Concatenated Seq: %s(%#v)\n", seq3, seq3) // {1, 2, 3, 4, 5}(NewSeq(1, 2, 3, 4, 5))

	// Mapを使って各要素を2倍にする
	doubledSeq := seq3.Map(func(x int) int {
		return x * 2
	})
	fmt.Println("Doubled Seq:", doubledSeq) // {2, 4, 6, 8, 10}

	// Filterを使って偶数を抽出
	evenSeq := seq3.Filter(func(x int) bool {
		return x%2 == 0
	})
	fmt.Println("Even Seq:", evenSeq) // {2, 4}

	// ForEachを使って各要素を表示
	seq3.ForEach(func(x int) {
		fmt.Println("ForEach element:", x)
	})

	// Reduceを使って合計を計算
	sum := seq3.Reduce(func(acc, x int) int {
		return acc + x
	}, 0)
	fmt.Println("Sum:", sum) // 15
}

脚註

[編集]