【问题标题】:Why does the function execution order seem reversed when I append function calls?当我追加函数调用时,为什么函数执行顺序似乎颠倒了?
【发布时间】:2019-02-08 04:16:46
【问题描述】:

我正在阅读这个问题:Decorator functions in Go,我想知道为什么接受答案中示例的执行顺序对我来说似乎相反。

我已将其分解为以下最小示例,我想知道效果是否是由于函数链接造成的。

// 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)
    }
}

正如代码中提到的,这会产生“DECORATED some_string golang”,表示函数是从左到右执行的,而普通函数是从最内到最外计算的,即从右到左。 [这让我想起了变换矩阵的后乘 - 顺序也是“颠倒的”,即 M_1 * M_2 * M_3] 这是由于函数链接还是什么原因?有人可以帮我详细了解这是如何执行的吗?

提前谢谢你。

【问题讨论】:

    标签: function go


    【解决方案1】:

    我重写了你的例子来说明。

    嵌套函数调用从内到外执行。每个函数调用都返回一个函数。最终变量m 被分配了AppendDecorator 的结果,它本身就是一个由所有装饰器组成的函数,看起来像这样:

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

    当我们执行m(s)(在fmt.Println(m(s)内部)时,我们正在执行AppendDecorator返回的函数。此函数调用m(s + x),其中mToLower 返回的函数。当此函数执行时,它调用m(lower),其中mPrependDecorator 返回的函数。当这个函数执行时,它会调用m(x + s),其中m是我们传入的Identity函数。

    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))
    }
    

    m := AppendDecorator(" GOLANG", ToLower(PrependDecorator("DECORATED ", Identity))) 的输出是:

    Returning Prepend manipulator
    Returning ToLower manipulator
    Returning Append manipulator
    

    fmt.Println(m(s)) 的输出是:

    Executing Append manipulator
    Executing ToLower manipulator
    Executing Prepend manipulator
    Executing Identity manipulator
    DECORATED some_string golang
    

    【讨论】:

    • 谢谢。这已经让它更清楚了,但我仍然很困惑为什么“返回附加操纵器”之后的步骤是“执行附加操纵器”而不是前置。 Haskell 也返回函数,但是当我执行 addFoo :: String -> String addFoo x = x ++ "Foo" addBar :: String -> String addBar x = x ++ "Bar" main :: IO () main = do ` print(addFoo(addBar "start"))` 时,它将像我预期的那样从内到外执行。我错过了什么?
    • 你的 Haskell 函数直接返回字符串。 Go 函数返回返回字符串的函数。然后执行返回的最终函数(由AppendDecorator),然后依次执行其余函数。我记不起足够的 Haskell 来编写等效函数,例如 appendDecorator :: (String -> String) -> String -> String
    • 再次感谢并抱歉这么密集,但我不能明确地编写函数,即print((addFoo . addBar) $ "start")吗?并且由于柯里化,这些应该返回实际的功能 - 例如addFoo 返回一个函数,该函数接受一个字符串并将“Foo”附加到它。但即使我明确组合了这些功能,我仍然会得到“startBarFoo”。也许我只需要睡在它上面。 [Append ++ is String -> String -> String 和你的陈述非常接近。]
    猜你喜欢
    • 2019-01-12
    • 2023-02-18
    • 2012-04-15
    • 1970-01-01
    • 2021-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-12
    相关资源
    最近更新 更多