方法表达式

我在看 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 的代码确实很优秀,需要斟酌思考。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容