Method chaining
- Go course
- Beginner
- Lesson 79/90
- 4 min
Learn to return the receiver for method chaining.
Method chaining
If a method returns the receiver (as a pointer), calls can be written one after another; this is called a fluent API:
type Sorgu struct{ parcalar []string }
func (s *Sorgu) Sec(a string) *Sorgu { s.parcalar = append(s.parcalar, "SELECT "+a); return s }
func (s *Sorgu) Tablo(t string) *Sorgu { s.parcalar = append(s.parcalar, "FROM "+t); return s }
func (s *Sorgu) String() string { return strings.Join(s.parcalar, " ") }
q := (&Sorgu{}).Sec("ad").Tablo("urunler")
fmt.Println(q) // SELECT ad FROM urunlerChaining with errors
Chaining isn't common in Go because it is hard to return an error in the middle of a chain. One solution is to store the error inside the object and check it at the end:
type Builder struct {
err error
// ...
}
func (b *Builder) Adim(x int) *Builder {
if b.err != nil {
return b // skip if there was an earlier error
}
if x < 0 {
b.err = errors.New("negatif değer")
}
return b
}bufio.Scanner's Err() method uses a similar idea.
Practice Query builder
Write the Sorgu type above with the Sec, Tablo and String methods, and also add Limit(n int) *Sorgu. Print the result of (&Sorgu{}).Sec("ad").Tablo("urunler").Limit(5).
Starter code
package main
import (
"fmt"
"strings"
)
func main() {
// buraya yaz
}Sample solution
package main
import (
"fmt"
"strings"
)
type Sorgu struct{ parcalar []string }
func (s *Sorgu) Sec(a string) *Sorgu {
s.parcalar = append(s.parcalar, "SELECT "+a)
return s
}
func (s *Sorgu) Tablo(t string) *Sorgu {
s.parcalar = append(s.parcalar, "FROM "+t)
return s
}
func (s *Sorgu) Limit(n int) *Sorgu {
s.parcalar = append(s.parcalar, fmt.Sprintf("LIMIT %d", n))
return s
}
func (s *Sorgu) String() string { return strings.Join(s.parcalar, " ") }
func main() {
fmt.Println((&Sorgu{}).Sec("ad").Tablo("urunler").Limit(5))
}Expected output
SELECT ad FROM urunler LIMIT 5
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 What should a chainable method's return type be?
- Nothing
- A pointer to its own type (*Sorgu) Correct answer
- error
- string
Explanation: Because each call returns the same object, the next method works on it.
2 Return the receiver
func (s *Sorgu) Limit(n int) *Sorgu {
s.parcalar = append(s.parcalar, fmt.Sprintf("LIMIT %d", n))
return ____
}
func (s *Sorgu) Limit(n int) *Sorgu {
s.parcalar = append(s.parcalar, fmt.Sprintf("LIMIT %d", n))
return s
}
Explanation: return s returns the same pointer so the chain can continue.
3 Part and role
| Term | Meaning |
|---|---|
Returning *Sorgu |
Keeps the chain going |
String() |
Turns the result into text |
b.err |
Stores an error in the chain |
(&Sorgu{}) |
Starting object |