Can anonymous function call be called?

I just go through the Tour of Go and get to exercise on the go. Its obvious recursion, but closing the pipe is a special case after the call stack is completely shut down. Anyway, I ended up implementing it by doing this:

// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
    var walker func(t *tree.Tree, ch chan int)
    walker = func(t *tree.Tree, ch chan int) {
        if (t.Left != nil) {
            walker(t.Left, ch)
        }
        ch <- t.Value
        if (t.Right != nil) {
            walker(t.Right, ch)
        }
    }
    walker(t, ch)
    close(ch)
}

      

My impression so far is that they prefer to avoid saying things if they can, so the declaration var walker

before definition seems to be off. Perhaps I missed some details that would allow a function to reference itself without a declaration? It would be slightly better if it were possible:

// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
    func(t *tree.Tree, ch chan int) {
        if (t.Left != nil) {
            __me__(t.Left, ch)
        }
        ch <- t.Value
        if (t.Right != nil) {
            __me__(t.Right, ch)
        }
    }(t, ch)
    close(ch)
}

      

It's a simple trivia question, but I'm new enough to a language I can't find an answer in ...

+3


source to share


3 answers


You cannot use a variable prior to its declaration, and it has not yet been declared in its initialization statement.



So yes, the declaration line is required, and no, there is no way to avoid it.

+4


source


I agree with @ milo-chirstiansen that an anonymous function cannot reference its instance in its declaration.

If you're trying to understand Go's idiomatic code, it might look a little different, eliminating the anonymous function:

// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
    Walker(t, ch)
    close(ch)
}

// Walker does the things, made to be called recursively
func Walker(t *tree.Tree, ch chan int) {
    if t.Left != nil {
        Walker(t.Left, ch)
    }
    ch <- t.Value
    if t.Right != nil {
        Walker(t.Right, ch)
    }
}

      


You may find this interesting ...



Go allows some cool things that are not possible in other languages. This sometimes requires thinking a little differently about your code.

Frances Campoy gave a speech at GopherCon 2016 about her legendary concept story nil

in Go. One of his examples of how to nil

be used nicely and idiomatically includes a solution to get the sum for a binary tree. Below is a link starting with this part of his conversation and I would recommend checking it out if you have time. ref: https://youtu.be/ynoY2xz-F8s?t=16m28s

I understand that you have no control over the Tree structure in your example, but if you did, this is how your code looks like: https://play.golang.com/p/iM10NQXfgw

package main

import "fmt"

// A Tree is a binary tree with integer values.
type Tree struct {
    Left  *Tree
    Value int
    Right *Tree
}

// Walk loads value into channel; caller is responsible for providing and closing chan
func (t *Tree) Walk(ch chan int) {

    // Super interesting: Go supports the calling of a func on a nil instance of a struct
    if t == nil {
        return // return nothing
    }

    t.Left.Walk(ch)  // recursively call Walk on left node
    ch <- t.Value
    t.Right.Walk(ch) // recursively call Walk on right node
}

func main() {
    // Initial value for our tree; I'm not being very idiomatic with this
    tree := &Tree{
        Left:  &Tree{Value: 2},
        Value: 1,
        Right: &Tree{Left: &Tree{Value: 4}, Value: 3},
    }

    ch := make(chan int)

    // Load values into chan in separate goroutine
    // to prevent blocking
    go func() {
        tree.Walk(ch)
        close(ch)
    }()

    // Write each val added to chan until all values
    // have been written and chan is closed
    for val := range ch {
        fmt.Println(val)
    }
}

      

1

2

3

4

+3


source


This can be avoided by combining runtime.Caller

and reflect.Call

.

But that nothing even looks like an idiomatic "Go", so I don't think this applies to your practical situation, although it does concern the letter of your question. :)

+1


source







All Articles