Returning File Pointer in Golang

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

Returning File Pointer in Golang

问题

我仍然在努力理解 Golang 的基础知识。

考虑以下示例代码:

  1. func OpenOutputFile(name string) (fp *os.File) {
  2. fp, err := os.Create(name)
  3. if err != nil {
  4. panic(err)
  5. }
  6. defer func() {
  7. if err := fp.Close(); err != nil {
  8. panic(err)
  9. }
  10. }()
  11. return fp
  12. }

我会假设调用:

  1. fp := OpenOutputFile("output.txt")

会使 fp 成为一个文件指针 (*os.File),这样我就可以在另一个函数中调用类似这样的语句:

  1. io.WriteString(fp, "Hello World")

但是,在调用这个方法时,会生成错误:

  1. 0 write output.txt: bad file descriptor

所以看起来返回的指针无效。我该如何返回一个正确形式的指针以便在 io.WriteString 中使用?

感谢您的帮助!

需要注意的是:当文件指针的创建和写入文件指针存在于同一个方法中时,一切都按预期执行。将逻辑拆分为一个函数会导致它无法按预期工作。

英文:

I'm still struggling with the basics of Golang.

Consider the following sample code:

  1. func OpenOutputFile(name string) (fp *os.File) {
  2. fp, err := os.Create(name)
  3. if err != nil {
  4. panic(err)
  5. }
  6. defer func() {
  7. if err := fp.Close(); err != nil {
  8. panic(err)
  9. }
  10. }()
  11. return fp
  12. }

I would assume that calling:

  1. fp := OpenOutputFile("output.txt")

would now make fp a file pointer (*os.File), so that I could call a statement like:

  1. io.WriteString(fp, "Hello World")

In another function. But when calling this method, the error is generated:

  1. 0 write output.txt: bad file descriptor

So it appears that the pointer returned is not valid. How can I return a properly formed pointer to use with io.WriteString?

I appreciate the help!

Of note: Everything executes as intended when the creation of the file pointer and the writing to the file pointer exists in the same method. Breaking the logic into a function causes it to not behave as intended.

答案1

得分: 7

《Go编程语言规范》

延迟语句

"defer"语句会调用一个函数,该函数的执行被延迟到包围它的函数返回的时刻,无论是因为包围的函数执行了一个返回语句,到达了函数体的末尾,还是因为相应的goroutine正在恐慌。

每次执行"defer"语句时,函数值和调用的参数会像平常一样被求值并重新保存,但实际的函数不会被调用。相反,延迟函数会在包围的函数返回之前立即被调用,按照它们被延迟的相反顺序。如果延迟函数的值求值为nil,在调用函数时会引发恐慌,而不是在执行"defer"语句时。

例如,如果延迟函数是一个函数字面量,并且包围的函数具有在字面量内部可见的命名结果参数,延迟函数可以在返回之前访问和修改结果参数。如果延迟函数有任何返回值,在函数完成时它们会被丢弃。

  1. func OpenOutputFile(name string) (fp *os.File) {
  2. fp, err := os.Create(name)
  3. if err != nil {
  4. panic(err)
  5. }
  6. defer func() {
  7. if err := fp.Close(); err != nil {
  8. panic(err)
  9. }
  10. }()
  11. return fp
  12. }

你打开文件

  1. fp, err := os.Create(name)

你关闭文件

  1. err := fp.Close()

Close之后,fp不再指向有效的文件描述符。

英文:

> The Go Programming Language Specification
>
> Defer statements
>
> A "defer" statement invokes a function whose execution is deferred to
> the moment the surrounding function returns, either because the
> surrounding function executed a return statement, reached the end of
> its function body, or because the corresponding goroutine is
> panicking.
>
> Each time a "defer" statement executes, the function value and
> parameters to the call are evaluated as usual and saved anew but the
> actual function is not invoked. Instead, deferred functions are
> invoked immediately before the surrounding function returns, in the
> reverse order they were deferred. If a deferred function value
> evaluates to nil, execution panics when the function is invoked, not
> when the "defer" statement is executed.
>
> For instance, if the deferred function is a function literal and the
> surrounding function has named result parameters that are in scope
> within the literal, the deferred function may access and modify the
> result parameters before they are returned. If the deferred function
> has any return values, they are discarded when the function completes.

  1. func OpenOutputFile(name string) (fp *os.File) {
  2. fp, err := os.Create(name)
  3. if err != nil {
  4. panic(err)
  5. }
  6. defer func() {
  7. if err := fp.Close(); err != nil {
  8. panic(err)
  9. }
  10. }()
  11. return fp
  12. }

You open the file

  1. fp, err := os.Create(name)

You close the file

  1. err := fp.Close()

After the Close, fp no longer points to a valid file descriptor.

答案2

得分: 0

将close函数返回并延迟在更高的作用域中对我起了作用。不过我不确定这是否是Go语言中的一个好实践。它依赖于在原始函数之外关闭/延迟执行。

  1. func OpenFileFromArgs() (*os.File, func()) {
  2. if len(os.Args) < 2 {
  3. panic("未提供输入文件")
  4. }
  5. inputFilePath := os.Args[1]
  6. stat, err := os.Stat(inputFilePath)
  7. if err != nil {
  8. if errors.Is(err, os.ErrNotExist) {
  9. panic(fmt.Sprintf("文件 %s 不存在", inputFilePath))
  10. } else {
  11. panic(fmt.Sprintf("错误:%v", err))
  12. }
  13. }
  14. if stat.IsDir() {
  15. panic("提供的路径是一个目录")
  16. }
  17. inputFile, err := os.Open(inputFilePath)
  18. closeFn := func() {
  19. err := inputFile.Close()
  20. if err != nil {
  21. panic("无法关闭输入文件")
  22. }
  23. }
  24. return inputFile, closeFn
  25. }

然后在更高的作用域中:

  1. inputFile, closeFn := library.OpenFileFromArgs()
  2. defer closeFn()

通过逐步调试确认 - 在程序结束时,延迟的关闭函数被正确调用,文件描述符被关闭。

英文:

Returning the close function and deferring it in higher scope worked for me. I don't know if this is a good practice in Go though. It relies on closing/deferring outside of original function:

  1. func OpenFileFromArgs() (*os.File, func()) {
  2. if len(os.Args) &lt; 2 {
  3. panic(&quot;input file not provided&quot;)
  4. }
  5. inputFilePath := os.Args[1]
  6. stat, err := os.Stat(inputFilePath)
  7. if err != nil {
  8. if errors.Is(err, os.ErrNotExist) {
  9. panic(fmt.Sprintf(&quot;file %s doens&#39;t exist&quot;, inputFilePath))
  10. } else {
  11. panic(fmt.Sprintf(&quot;error: %v&quot;, err))
  12. }
  13. }
  14. if stat.IsDir() {
  15. panic(&quot;provided path is a directory&quot;)
  16. }
  17. inputFile, err := os.Open(inputFilePath)
  18. closeFn := func() {
  19. err := inputFile.Close()
  20. if err != nil {
  21. panic(&quot;failed to close input file&quot;)
  22. }
  23. }
  24. return inputFile, closeFn

and then in the higher scope:

  1. inputFile, closeFn := library.OpenFileFromArgs()
  2. defer closeFn()

Confirmed using step by step debugger - at program end, the deferred close function is correctly called and file descriptor closed.

huangapple
  • 本文由 发表于 2016年3月20日 11:22:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/36109887.html
匿名

发表评论

匿名网友

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

确定