douyi6922 2019-02-08 04:16
浏览 52
已采纳

为什么追加函数调用时函数执行顺序看起来相反?

I was reading this question: Decorator functions in Go and am wondering why the execution order of the example in the accepted answer seems reversed to me.

I have broken it down to the following minimal example and am wondering if the effect is due to function chaining.

// Interesting Part
some_string := "Some_String"
var fn3 StringManipulator = ident
fn3 = AppendDecorator(" GOLANG", ToLower(PrependDecorator("DECORATED ", fn3)))
fmt.Println(fn3(some_string))
// Prints "DECORATED some_string golang"

// Function Definitions
func ToLower(m StringManipulator) StringManipulator {
    return func(s string) string {
        lower := strings.ToLower(s)
        return m(lower)
    }
}

func AppendDecorator(x string, m StringManipulator) StringManipulator {
        return func(s string) string {
            return m(s + x)
        }
}

func PrependDecorator(x string, m StringManipulator) StringManipulator {
    return func(s string) string {
        return m(x + s)
    }
}

As mentioned in the code this yields "DECORATED some_string golang" indicating that the functions were executed from left to right, whereas normal functions evaluate from innermost to outermost, i.e. right to left. [This reminds me of postmultiplication of transformation matrices - there the order is also "reversed", i.e. M_1 * M_2 * M_3] Is this due to function chaining or what is the reason? Could somebody help me understand how this executes in detail?

Thank you in advance.

  • 写回答

1条回答 默认 最新

  • duanaoshu1989 2019-02-08 04:45
    关注

    I rewrote your example to illustrate.

    The nested function calls execute from inside to outside. Each function call returns a function. Eventually the variable m is assigned the result of AppendDecorator which is itself a function composed of all the decorators that looks something like this:

    m := func(s string) string {
        return ("DECORATED " + strings.ToLower(s + " GOLANG"))
    }
    

    When we execute m(s) (inside fmt.Println(m(s)) we are executing the function returned by AppendDecorator. This function calls m(s + x) where m is the function returned by ToLower. When this function executes it calls m(lower) where m is the function returned by PrependDecorator. When this function executes it calls m(x + s) where m is the Identity function that we passed in.

    package main
    
    import (
        "fmt"
        "strings"
    )
    
    // StringManipulator manipulate a string
    type StringManipulator func(str string) string
    
    // Identity a string manipulator that leaves the string unchanged
    func Identity(s string) string {
        fmt.Println("Executing Identity manipulator")
        return s
    }
    
    // ToLower a lower case string manipulator
    func ToLower(m StringManipulator) StringManipulator {
        fmt.Println("Returning ToLower manipulator")
        return func(s string) string {
            fmt.Println("Executing ToLower manipulator")
            lower := strings.ToLower(s)
            return m(lower)
        }
    }
    
    // AppendDecorator append a string manipulator
    func AppendDecorator(x string, m StringManipulator) StringManipulator {
        fmt.Println("Returning Append manipulator")
        return func(s string) string {
            fmt.Println("Executing Append manipulator")
            return m(s + x)
        }
    }
    
    // PrependDecorator prepend a string manipulator
    func PrependDecorator(x string, m StringManipulator) StringManipulator {
        fmt.Println("Returning Prepend manipulator")
        return func(s string) string {
            fmt.Println("Executing Prepend manipulator")
            return m(x + s)
        }
    }
    
    func main() {
        s := "Some_String"
    
        m := AppendDecorator(" GOLANG", ToLower(PrependDecorator("DECORATED ", Identity)))
        fmt.Println(m(s))
    }
    

    The output from m := AppendDecorator(" GOLANG", ToLower(PrependDecorator("DECORATED ", Identity))) is:

    Returning Prepend manipulator
    Returning ToLower manipulator
    Returning Append manipulator
    

    and the output from fmt.Println(m(s)) is:

    Executing Append manipulator
    Executing ToLower manipulator
    Executing Prepend manipulator
    Executing Identity manipulator
    DECORATED some_string golang
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 IAR程序莫名变量多重定义
  • ¥15 (标签-UDP|关键词-client)
  • ¥15 关于库卡officelite无法与虚拟机通讯的问题
  • ¥100 已有python代码,要求做成可执行程序,程序设计内容不多
  • ¥15 目标检测项目无法读取视频
  • ¥15 GEO datasets中基因芯片数据仅仅提供了normalized signal如何进行差异分析
  • ¥100 求采集电商背景音乐的方法
  • ¥15 数学建模竞赛求指导帮助
  • ¥15 STM32控制MAX7219问题求解答
  • ¥20 在本地部署CHATRWKV时遇到了AttributeError: 'str' object has no attribute 'requires_grad'