为什么我的函数没有返回?

Below is a function that starts an external process, matches a regular expression against the process' standard output, and returns the contents of the match.

func (c *Colony) startCircuit(peer *string) (string, error) {
    var (
        err        error
        cmd        *exec.Cmd
        anchorChan chan string
    )

    // ... (omitted for readability)

    // get the anchor from standard output
    go func() {
        defer out.Close()

        anchorChan = make(chan string)
        for scanner := bufio.NewScanner(out); scanner.Scan(); {
            line := scanner.Text()
            if anchor := reRootAnchor.FindString(line); anchor != "" {
                log.Println("Started circuit server with anchor:", anchor)
                anchorChan <- anchor
                break
            }
        }
    }()

    anchor := <-anchorChan
    return anchor, err
}

When running the function, I obtain the following output, which shows that a match is indeed found and (presumably) pushed into anchorChan:

2016/05/22 14:04:36 Started circuit server with anchor: circuit://[::]:36195/20666/Q431cc5fe613aa04b

However, startCircuit's caller seems to hang. Here is the relevant bit of code:

rootAnchor, err := c.startCircuit(peer)
if err != nil {
    return "", err
}
log.Fatal(rootAnchor) // DEBUG

Why is startCircuit hanging indefinitely instead of returning?

The problem is in fact quite simple. Hint: the following code ends in a deadlock.

package main

import "fmt"

func main() {
    var c chan string

    go func() {
        c = make(chan string)
        c <- "42"
    }()

    str := <-c
    fmt.Println(str)
}

From there, the problem is trivial. Your channel is not initialized when you start the goroutine. There is a race with the two goroutines, and apparently go cannot decide which should have the priority.

So, your answer is: call make(chan ...) before the goroutine starts, it should solve your problem. There is a perfect example of this in effective go.

Dave Cheney has a good related blog post: http://dave.cheney.net/2014/03/19/channel-axioms

Most relevant points:

  1. A send to a nil channel blocks forever
  2. A receive from a nil channel blocks forever

Since uninitialized channel is nil, and thus any read and write to it will result in deadlock. In example, in T. Claverie's answer, there is a race: If c = make(chan string), (and c <- "42", I believe that str := <-c has to wait at this point) happen first, then receive happens from initialized, non-empty channel and everything is runs fine:

package main

import "fmt"
import "time"

func main() {
    var c chan string

    go func() {
        c = make(chan string)
        c <- "42"
    }()

    time.Sleep(time.Second * 1)
    str := <-c
    fmt.Println(str)
}

go playground

You can run the above example to convince yourself. (This is not good practice or even guaranteed to work every time.)

However, if str := <-c happens first, then you are receiving from an nil channel, which results in a deadlock.