我在看 exec 包的时候发现 cmd 在 start 的时候有这样的一段代码
...
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 的几个方法,是方法而不是函数。但是 F 其实是一个函数,他没有接受者,但是函数第一个参数也就是 receiver。
方法和函数的区别在于有没有 receiver
所以做如下实验。。。
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")
}
// 方法表达式
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)
}
}
通过这种方式可以很简单去调用一个结构体下同一类型的方法,否则代码会写成这样
func TestMethodFuc2(t *testing.T) {
var p People
p.sing()
p.jump()
p.rpa()
p.basketball()
}
虽然更清晰了,但是考虑一下处理 error 会发现 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
}
// 方法表达式
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)
}
}
明显上面的处理方式更为简单清晰,sdk 的代码确实很优秀,需要斟酌思考。