我阅读了exec.Start的代码,有些内容令我困惑。 (* Cmd)。[/ f]中的.stdin / out / err,(* Cmd).stdXX的含义是什么?
291 type F func(*Cmd) (*os.File, error)
292 for _, setupFd := range []F{(*Cmd).stdin, (*Cmd).stdout, (*Cmd).stderr} {
293 fd, err := setupFd(c)
294 if err != nil {
295 c.closeDescriptors(c.closeAfterStart)
296 c.closeDescriptors(c.closeAfterWait)
297 return err
298 }
299 c.childFiles = append(c.childFiles, fd)
300 }
答案 0 :(得分:5)
很好找,我之前不知道那个成语。我会试着把它分解。 首先我们有exec.Cmd
type exec.Cmd struct { ... }
*Cmd
有3种方法,包括stdin
stdout
stderr
func (c *Cmd) stdin() (f *os.File, err error) {...}
func (c *Cmd) stdout() (f *os.File, err error) {...}
func (c *Cmd) stderr() (f *os.File, err error) {...}
现在我想调用所有这些函数并对每个函数执行相同的操作,但我不想创建另一个方法,因为有太多的共享变量要通过参数传递。
第一个解决方案是将代码复制/粘贴3次。不好。
第二种是循环遍历 Functors 的数组。 Functor类型为func(c*Cmd)(f *os.File, err error)
,因此我们将其声明为
type F (c *Cmd) (f *os.File, err error)
现在我们可以创建一个仿函数数组。但是如何选择*Cmd
方法呢?只需使用
(*Cmd).<name of method>
所以它会(*Cmd).stdin, (*Cmd.stdout), (*Cmd).stderr
我们可以将它们用作数组
[]F{ (*Cmd).stdin, (*Cmd.stdout), (*Cmd).stderr }
我们现在只需要打电话给他们
for _, setupFd := range []F{(*Cmd).stdin, (*Cmd).stdout, (*Cmd).stderr} {
fd, err := setupFd(c)
...
}
希望这有帮助。
答案 1 :(得分:1)
我以前从未遇到的一个非常有趣的习语。该代码将*Cmd
方法作为函数,并在c
上按顺序调用它们。这是一个更简单的代码示例,展示了它的工作原理:http://play.golang.org/p/XwuYD_9uGs。
该代码也可以写成for
身体,用三个不同的stdXX
调用,但这会重复且容易出错,因此作者决定在一个循环中应用三种方法。