Как понять этот рекурсивный результат - PullRequest
0 голосов
/ 13 января 2019

Я написал ошибку во время кодирования, когда я решил проблему, я был озадачен выводом кода, код показывается ниже:

type (
    Handler func(name string) error
)

func mh(h Handler) Handler {
    return func(name string) error {
        fmt.Printf("return mh,name=%s,h=%x\n", name, h)
        return h(name)
    }
}

func main() {
    var h Handler
    h = func(name string) error {
        fmt.Printf("********************************\n")
        fmt.Printf("before func h=%x\n", h)
        h = mh(h)
        fmt.Printf("after func h=%x\n", h)
        return h(name)
    }
    fmt.Printf("main h=%x\n", h)
    h("main")
}

Выполнение кода, вывод:

main h=486d40
********************************
before func h=486d40
after func h=486c00
return mh,name=main,h=486d40
********************************
before func h=486c00
after func h=486c00
return mh,name=main,h=486c00
return mh,name=main,h=486d40
********************************
before func h=486c00
after func h=486c00
return mh,name=main,h=486c00
return mh,name=main,h=486c00
return mh,name=main,h=486d40
.......

Я не понимаю стек вызовов. Я думал, что выводом должен быть цикл "mh".

Ответы [ 2 ]

0 голосов
/ 14 января 2019

Ключевым моментом для понимания является то, что эта строка:

h = mh(h)

Вызывает ли функцию h. Он вызывает функцию mh(), которая просто возвращает значение функции, но также не вызывает h(). Если будет возвращено значение функции, это вызовет h().

Таким образом, функция main() сохраняет значение функции в h, а затем вызывает h().

Этот h() печатает "before", затем переносит h в другую функцию и сохраняет результат в h, затем печатает "after". Важно знать, что функция-обертка (значение, возвращаемое mh()) является замыканием и хранит исходное значение h, поэтому присвоение результата h не влияет на h внутри обернутого функция.

Итак, h заканчивается вызовом h, который теперь является упакованной функцией. Обернутая функция начинается с печати "return", затем она вызывает оригинал, развернутый h.

Оригинал, развернутый h, снова печатает "before", затем переносит текущее значение h (которое является функцией переноса), сохраняет его в h, затем печатает "after".

И затем вызывает h, который теперь представляет собой двойную упакованную функцию. Он начинается с печати "return", а затем вызывает сохраненное значение h, которое является однократной упакованной функцией. Функция однократного переноса начинается с печати "return" (снова), затем продолжается с исходной, которая печатает "before", переносит h, который теперь будет переноситься 3 раза, сохраняет ее в h, затем вызывает h (что является значением функции с 3-кратным переносом) ...

Эта логика продолжается, значение функции, хранящееся в h, будет упаковываться все больше и больше, а функция с переносом всегда будет иметь сохраненное значение однократного переноса предыдущей функции.

По мере продолжения «итерации» «глубина переноса» увеличивается, поэтому вы увидите все больше и больше напечатанных операторов "return" (как и делает перенос).

0 голосов
/ 13 января 2019

Виновным является это назначение:

  h = mh(h) 

Заменяет привязку h в main от анонимной функции, которая печатает до / после, к тому, что mh возвращает.

Если вы замените

    h = mh(h)    
    fmt.Printf("after func h=%x\n", h)    
    return h(name)

С

    return mh(h)(name)

Вы получите ожидаемую взаимную рекурсию

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...