2014-07-09 62 views
3

我讀了exec.Start的代碼,有一部分讓我困惑。 (* Cmd).stdin/out/err在[] F中,(* Cmd).stdXX的含義是什麼?exec.start中的這部分代碼是什麼意思?

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

解引用'Cmd',它是一個指針,這樣'(* Cmd)'是一個對象並且調用該對象的一個​​方法。死簡單,而不是一個答案。 – Volker

+4

我不認爲這很簡單:'Cmd'是一個類型,而不是一個變量名。我錯了嗎? – julienc

回答

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次。不太好。

第二個是循環遍歷函子。仿函數類型是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

[它們只是普通的常規函數​​。](http://stackoverflow.com/a/15328868/532430)接收器只是語法糖。 – thwd

1

一個非常有趣的成語,我從來沒有遇到過。代碼以*Cmd的方法作爲函數,並在c上按順序調用它們。下面是一個簡單的代碼示例,顯示它的工作原理:http://play.golang.org/p/XwuYD_9uGs

該代碼也可以寫成for正文用三個不同的stdXX調用,但這會重複且容易出錯,因此作者決定在一個循環中應用三種方法。