Go/メソッドチェイン
表示
< 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 } } } } // 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 } // Drop はSeqの先頭からn個の要素を削除 func (seq Seq[T]) Drop(n int) Seq[T] { return func(yield func(T) bool) { count := 0 seq(func(v T) bool { if count < n { count++ return true } return yield(v) }) } } // Take はSeqの先頭からn個の要素を取得 func (seq Seq[T]) Take(n int) Seq[T] { return func(yield func(T) bool) { count := 0 seq(func(v T) bool { if count < n { count++ return yield(v) } return false }) } } // 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をスライスに変換(JSのtoArray()相当) func ToSlice[T any](seq Seq[T]) []T { var result []T seq(func(v T) bool { result = append(result, v) return true }) return result } // ToArray はSeqをスライスに変換(JSのtoArray()と同等) func (seq Seq[T]) ToArray() []T { return ToSlice(seq) } // Every はすべての要素が条件を満たすか確認(JSのevery()相当) func (seq Seq[T]) Every(fn func(T) bool) bool { result := true seq(func(v T) bool { if !fn(v) { result = false return false // 一つでも条件を満たさない要素があれば中断 } return true }) return result } // Some は少なくとも一つの要素が条件を満たすか確認(JSのsome()相当) func (seq Seq[T]) Some(fn func(T) bool) bool { result := false seq(func(v T) bool { if fn(v) { result = true return false // 一つでも条件を満たす要素があれば中断 } return true }) return result } // Find は条件を満たす最初の要素を見つける(JSのfind()相当) func (seq Seq[T]) Find(fn func(T) bool) (T, bool) { var found T foundAny := false seq(func(v T) bool { if fn(v) { found = v foundAny = true return false // 条件を満たす要素を見つけたら中断 } return true }) return found, foundAny } // FlatMap は各要素にマッピング関数を適用し、結果をフラット化(JSのflatMap()相当) func (seq Seq[T]) FlatMap(fn func(T) Seq[T]) Seq[T] { return func(yield func(T) bool) { seq(func(v T) bool { innerSeq := fn(v) continueOuter := true innerSeq(func(innerV T) bool { if !yield(innerV) { continueOuter = false return false } return true }) return continueOuter }) } } // 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 seq := NewSeq(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) // Dropのテスト droppedSeq := seq.Drop(3) fmt.Println("Dropped Seq:", droppedSeq) // {4, 5, 6, 7, 8, 9, 10} // Takeのテスト takenSeq := seq.Take(5) fmt.Println("Taken Seq:", takenSeq) // {1, 2, 3, 4, 5} // DropとTakeの組み合わせ combinedSeq := seq.Drop(2).Take(3) fmt.Println("Combined Seq:", combinedSeq) // {3, 4, 5} // 新しく追加したメソッドのテスト // Everyのテスト allLessThan11 := seq.Every(func(x int) bool { return x < 11 }) allEven := seq.Every(func(x int) bool { return x%2 == 0 }) fmt.Println("All less than 11:", allLessThan11) // true fmt.Println("All even:", allEven) // false // Someのテスト hasEven := seq.Some(func(x int) bool { return x%2 == 0 }) hasNegative := seq.Some(func(x int) bool { return x < 0 }) fmt.Println("Has even numbers:", hasEven) // true fmt.Println("Has negative numbers:", hasNegative) // false // Findのテスト firstEven, foundEven := seq.Find(func(x int) bool { return x%2 == 0 }) firstBig, foundBig := seq.Find(func(x int) bool { return x > 100 }) fmt.Println("First even number:", firstEven, "Found:", foundEven) // 2 true fmt.Printf("First number > 100: %v Found: %v\n", firstBig, foundBig) // 0 false // FlatMapのテスト poweredSeq := seq.Take(3).FlatMap(func(x int) Seq[int] { return NewSeq(x, x*x) }) fmt.Println("FlatMapped powered sequence:", poweredSeq) // {1, 1, 2, 4, 3, 9} // ToArrayのテスト array := seq.Take(4).ToArray() fmt.Println("ToArray result:", array) // [1 2 3 4] }