这段代码`exec.start`的含义是什么?

huangapple go评论87阅读模式
英文:

what's this part of code in exec.start means?

问题

我阅读了exec.Start的代码,有一部分让我感到困惑。在[]F中,(*Cmd).stdin/out/err的含义是什么?

代码中的(*Cmd).stdin/out/err是指向Cmd结构体的方法,它们分别表示标准输入、标准输出和标准错误输出。在循环中,通过调用这些方法来设置文件描述符,并将其添加到c.childFiles中。

英文:

I read the code of exec.Start,and there some part confusing me. (*Cmd).stdin/out/err in the []F,what's the meaning of (*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		}

答案1

得分: 5

非常好的发现,我之前不知道这个成语。我将尝试解释一下。

首先,我们有exec.Cmd

type exec.Cmd struct { ... }

*Cmd有3个方法,包括stdinstdoutstderr

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次,但这样不好。

第二种解决方案是循环遍历一个Functor数组。Functor类型将是func(c *Cmd) (f *os.File, err error),所以我们将其声明为

type F func(c *Cmd) (f *os.File, err error)

现在我们可以创建Functor数组。但如何选择一个*Cmd方法呢?简单地使用

(*Cmd).<方法名>

所以它将是(*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)
    ...
}

希望这可以帮到你。

英文:

Very Nice find, I did not know that idiom before. I will try to break it down.
First We have exec.Cmd

type exec.Cmd struct { ... }

*Cmd has 3 many methods including 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) {...}

Now I want to call all these functions and do the same set of operations on each of them but I don't want to create another method because there are too many shared variable to pass by arguments.

The first solution would be to just copy / paste the code 3 times. not nice.

The second is to loop over an array of Functors. The Functor type would be func(c*Cmd)(f *os.File, err error) so we declare it as

type F (c *Cmd) (f *os.File, err error)

now we can create the array of functors. But how to select a *Cmd method ? simply using

(*Cmd).&lt;name of method&gt;

So it would be (*Cmd).stdin, (*Cmd.stdout), (*Cmd).stderr
and we can use them as An array

[]F{ (*Cmd).stdin, (*Cmd.stdout), (*Cmd).stderr }

we just need to call them now

for _, setupFd := range []F{(*Cmd).stdin, (*Cmd).stdout, (*Cmd).stderr} {
    fd, err := setupFd(c)
    ...
}

Hope this helps.

答案2

得分: 1

我从未遇到过的一个非常有趣的成语。该代码将*Cmd的方法作为函数,并按顺序在c上调用它们。这里有一个更简单的代码示例,展示了它的工作原理:http://play.golang.org/p/XwuYD_9uGs。

这段代码也可以写成使用三个不同的stdXX调用for循环体,但那样会重复且容易出错,所以作者决定改为在循环中应用三个方法。

英文:

A very interesting idiom I have never encountered before. The code takes *Cmd's methods as functions and calls them in order on c. Here is a simpler code example that shows how it works: http://play.golang.org/p/XwuYD_9uGs.

That code could as well be written as for body called with three different stdXX, but that would be repetitive and bug-prone, so the author decided instead to apply three methods in a cycle.

huangapple
  • 本文由 发表于 2014年7月9日 23:21:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/24657605.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定