用于抽象资源分配/释放的Go语言惯用写法

huangapple go评论72阅读模式
英文:

Idiomatic Go for abstracting resource allocation/deallocation

问题

有没有一种Go的惯用方式来抽象资源的分配和释放?我最初的想法是在一个高阶函数中抽象出分配和释放的过程:

func withResource(f func(Resource) error) error {
    // 分配资源
    // 延迟释放资源
    return f(resource)
}

然而,这种思路直接借用了函数式范式,并不太符合Go的主要命令式特性。

作为一个具体的例子,在我的当前项目中,运行一个守护进程以执行一段代码是一个经常出现的主题,所以我创建了一个withDaemon函数来抽象这种共性:

func withDaemon(
    cmd *exec.Cmd,
    f func(io.ReadCloser, io.ReadCloser, io.WriteCloser) error,
) error {
    stdout, err := cmd.StdoutPipe()
    if err != nil {
        return fmt.Errorf("无法获取标准输出:%v", err)
    }

    stderr, err := cmd.StdoutPipe()
    if err != nil {
        return fmt.Errorf("无法获取标准错误:%v", err)
    }

    stdin, err := cmd.StdinPipe()
    if err != nil {
        return fmt.Errorf("无法获取标准输入:%v", err)
    }

    if err := cmd.Start(); err != nil {
        return fmt.Errorf("启动失败:%v", err)
    }

    defer func() {
        cmd.Process.Kill()
        cmd.Wait()
    }()

    return f(stdout, stderr, stdin)
}

以上是翻译好的内容,请确认是否满意。

英文:

Is there an idiomatic Go way for abstracting resource allocation/deallocation? My initial guess is to abstract the allocation/deallocation in a higher-order function:

func withResource(f func(Resource)error) error {
    // allocate resource
    // defer free resource
    return f(resource)
}

However, this line of thinking is borrowed directly from the functional paradigm and doesn't seem to align well with Go's largely imperative nature.

As a concrete example, running a daemon for the duration of a block of code is a recurring theme in my current project, so I've created a withDaemon function to abstract the commonality:

func withDaemon(
	cmd *exec.Cmd,
	f func(io.ReadCloser, io.ReadCloser, io.WriteCloser) error,
) error {
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return fmt.Errorf("couldn't get stdout: %v", err)
	}

	stderr, err := cmd.StdoutPipe()
	if err != nil {
		return fmt.Errorf("couldn't get stderr: %v", err)
	}

	stdin, err := cmd.StdinPipe()
	if err != nil {
		return fmt.Errorf("couldn't get stdin: %v", err)
	}

	if err := cmd.Start(); err != nil {
		return fmt.Errorf("failed to start: %v", err)
	}

	defer func() {
		cmd.Process.Kill()
		cmd.Wait()
	}

	return f(stdout, stderr, stdin)
}

答案1

得分: 6

我认为惯用的方式是创建一个守护进程类型,并在调用者中使用defer:

d := NewDaemon(...)
defer d.Stop()
doWhatever()
英文:

I think that the idiomatic way would be to create a Daemon type, and to just use defer in the caller:

d := NewDaemon(...)
defer d.Stop()
doWhatever()

huangapple
  • 本文由 发表于 2015年5月17日 00:13:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/30277927.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定