golang中是否存在惯用的范围语义?

时间:2015-01-27 12:11:19

标签: go deferred idiomatic scoped-lock

我想知道是否有任何惯用的方式来表示作用域语义。通过范围我的意思是:

  • 作用域的互斥锁(oneliner而不是显式锁定+ deffered解锁),
  • 记录功能(或任何代码块)入口和出口,
  • 测量执行时间。

前两个项目符号的示例代码:

package main

import "log"
import "sync"

func Scoped(m *sync.Mutex) func() {
    m.Lock()
    return func() {
        m.Unlock()
    }
}

func Log(what string) func() {
    log.Println(what, "started")
    return func() {
        log.Println(what, "done")
    }
}

func main() {
    defer Log("testing")()

    m := &sync.Mutex{} // obviously mutex should be from other source in real life
    defer Scoped(m)()
    // use m
}

https://play.golang.org/p/33j-GrBWSq

基本上我们需要一个函数调用刚才(例如互斥锁),一个调用应该推迟推迟(例如互斥锁解锁)。我建议在这里返回未命名的函数,但它可以很容易地命名(返回带有函数字段的struct)。

只有一个问题:用户可能忘记“呼叫”第一次呼叫的结果。

这段代码是(可以)惯用的吗?

4 个答案:

答案 0 :(得分:4)

我不相信有这样的惯用方法。我不确定你为什么要这样做,写起来真是太糟糕了

m.Lock()
defer m.Unlock()

答案 1 :(得分:3)

您提出的解决方案已经很好了。您返回func类型的值,您还必须在defer的末尾调用该值。

您可以避免这种情况(返回func值),但必须有2个函数调用,一个记录 start 事件,另一个记录 end 事件。

替代方法是进行函数调用,该函数调用生成延迟函数的参数值(而不是返回函数),该函数使用defer语句进行求值,这样它仍然可以保持一行

您也可以在Go Playground上尝试:

func start(s string) string {
    fmt.Println("Started", s)
    return s
}

func end(name string) {
    fmt.Println("Ended", name)
}

func main() {
    defer end(start("main"))

    fmt.Println("Doing main's work...")
}

输出:

Started main
Doing main's work...
Ended main

答案 2 :(得分:1)

将匿名函数作为范围

func() {
    Entrance()
    defer Exit()
    // anything you want to do in this scope
}()

答案 3 :(得分:0)

我认为问题与Go惯用性无关,似乎当函数在调用时表现相同时,通常会更好地推理代码。为了保持状态,我最好制作一个对象,并将函数定义为该对象的方法。意味着类似

type message string
func (foo message) Log(bar string){
    if bar==nil{doSomethingSpecial()}
    switch foo{
        case something: doSomething()
        ...
        case nil: doSomethingInitial()
        default: doDefault()
    }   
    log.Println(bar, "started")
    foo=bar
}