我在看 exec 包的時(shí)候發(fā)現(xiàn) cmd 在 start 的時(shí)候有這樣的一段代碼
...
type F func(*Cmd) (*os.File, error)
for _, setupFd := range []F{(*Cmd).stdin, (*Cmd).stdout, (*Cmd).stderr} {
fd, err := setupFd(c)
if err != nil {
c.closeDescriptors(c.closeAfterStart)
c.closeDescriptors(c.closeAfterWait)
return err
}
c.childFiles = append(c.childFiles, fd)
}
...
這樣一段代碼到底是什么意思,源碼中 stdin,stdout,stderr 是 *Cmd 作為 receiver 的幾個(gè)方法,是方法而不是函數(shù)。但是 F 其實(shí)是一個(gè)函數(shù),他沒(méi)有接受者,但是函數(shù)第一個(gè)參數(shù)也就是 receiver。
方法和函數(shù)的區(qū)別在于有沒(méi)有 receiver
所以做如下實(shí)驗(yàn)。。。
type People struct{}
func (p *People) sing() {
fmt.Println("sing")
}
func (p *People) jump() {
fmt.Println("jump")
}
func (p *People) rpa() {
fmt.Println("rpa")
}
func (p *People) basketball() {
fmt.Println("basketball")
}
// 方法表達(dá)式
func TestMethodFuc(t *testing.T) {
var p People
type F func(people *People)
for _, f := range []F{(*People).sing, (*People).jump, (*People).rpa, (*People).basketball} {
f(&p)
}
}
通過(guò)這種方式可以很簡(jiǎn)單去調(diào)用一個(gè)結(jié)構(gòu)體下同一類(lèi)型的方法,否則代碼會(huì)寫(xiě)成這樣
func TestMethodFuc2(t *testing.T) {
var p People
p.sing()
p.jump()
p.rpa()
p.basketball()
}
雖然更清晰了,但是考慮一下處理 error 會(huì)發(fā)現(xiàn) TestMethodFuc2 及其啰嗦。
type People struct{}
func (p *People) sing() error {
fmt.Println("sing")
return nil
}
func (p *People) jump() error {
fmt.Println("jump")
return nil
}
func (p *People) rpa() error {
fmt.Println("rpa")
return nil
}
func (p *People) basketball() error {
fmt.Println("basketball")
return nil
}
// 方法表達(dá)式
func TestMethodFuc1(t *testing.T) {
var p People
type F func(people *People) error
for _, f := range []F{(*People).sing, (*People).jump, (*People).rpa, (*People).basketball} {
if err := f(&p); err != nil {
t.Fatal(err)
}
}
}
func TestMethodFuc2(t *testing.T) {
var p People
if err := p.sing(); err != nil {
t.Fatal(err)
}
if err := p.jump(); err != nil {
t.Fatal(err)
}
if err := p.rpa(); err != nil {
t.Fatal(err)
}
if err := p.basketball(); err != nil {
t.Fatal(err)
}
}
明顯上面的處理方式更為簡(jiǎn)單清晰,sdk 的代碼確實(shí)很優(yōu)秀,需要斟酌思考。