分享到:文章主题: 请教两个Go的新手问题
raaay0608楼主
raaay0608
等级
用户
文章
386
积分
6748
星座
双子座
发信人: raaay0608 (raaay0608), 信区: Golang
标  题: 请教两个Go的新手问题
发信站: 北邮人论坛 (Tue May 15 11:54:46 2018), 站内

首先第一个是defer和err处理的顺序问题,应该先做哪一步的问题,比如如下两种写法

```go
func f1() {
    f, err := os.Open("/file.txt")
    if (err != nil) {
        return
    }
    defer f.Close()
}

func f2() {
    f, err := os.Open("/file.txt")
    defer f.Close()
    if (err != nil) {
        return
    }
}
```

哪一种应该算是正确的呢?

第二个问题是,Go垃圾回收也会回收指针,比如`f, _ := os.Open("file.txt")`后,如果没有调用`f.Close()`,垃圾回收的时候Runtime会做“善后”工作吗?



--

※ 来源:·北邮人论坛 http://bbs.byr.cn·[FROM: 2001:da8:215:c5e7:48af:14dc:c87d:*]
    返回顶部
    cc19931002沙发
    啦啦
    等级
    用户
    文章
    387
    积分
    6512
    星座
    天秤座
    发信人: cc19931002 (啦啦), 信区: Golang
    标  题: Re: 请教两个Go的新手问题
    发信站: 北邮人论坛 (Tue May 15 13:53:14 2018), 站内

    感觉第二种比较好
    --

    ※ 来源:·北邮人论坛 http://bbs.byr.cn·[FROM: 10.108.216.*]
      返回顶部
      lsp板凳
      doombaba
      等级
      用户
      文章
      1749
      积分
      17154
      星座
      双鱼座
      发信人: lsp (doombaba), 信区: Golang
      标  题: Re: 请教两个Go的新手问题
      发信站: 北邮人论坛 (Wed May 16 13:16:33 2018), 站内

      第一种比较好;不会
      --

      ※ 来源:·北邮人论坛 http://bbs.byr.cn·[FROM: 111.204.243.*]
        返回顶部
        lzj0218第3楼
        Snail
        等级
        用户
        文章
        442
        积分
        10897
        星座
        水瓶座
        发信人: lzj0218 (Snail), 信区: Golang
        标  题: Re: 请教两个Go的新手问题
        发信站: 北邮人论坛 (Wed May 16 20:43:25 2018), 站内

        第一个问题,《The Go Programming Language》中建议在打开资源后立即使用`defer`写好关闭资源的操作
        而且第一种写法实际上是错误的,在`err != nil`时,`defer`后面的`f.Close()`函数不会执行到
        楼主可以运行一下下面这段代码就看得出来了
        
        ```Go
        package main
        
        import "os"
        import "fmt"
        
        func f1() {
            _, err := os.Open("/file.txt")
            if (err != nil) {
                return
            }
            defer func() {
                fmt.Println("f1: hello world!")
            }()
        }
        
        func f2() {
            _, err := os.Open("/file.txt")
            defer func() {
                fmt.Println("f2: hello world!")
            }()
            if (err != nil) {
                return
            }
        }
        
        func main() {
            f1()
            f2()
        }
        ```
        
        第二个问题,垃圾回收的时候应该都不会做关闭资源这些操作吧,Go具体怎么做的不是很清楚

        --
        ※ 修改:·lzj0218 于 May 16 20:45:03 2018 修改本文·[FROM: 120.52.147.*]
        ※ 来源:·北邮人论坛 http://bbs.byr.cn·[FROM: 120.52.147.*]
          返回顶部
          lsp第4楼
          doombaba
          等级
          用户
          文章
          1749
          积分
          17154
          星座
          双鱼座
          发信人: lsp (doombaba), 信区: Golang
          标  题: Re: 请教两个Go的新手问题
          发信站: 北邮人论坛 (Sat May 19 23:24:52 2018), 站内


          【 在 lzj0218 的大作中提到: 】
          : [md]
          : 第一个问题,《The Go Programming Language》中建议在打开资源后立即使用`defer`写好关闭资源的操作
          : 而且第一种写法实际上是错误的,在`err != nil`时,`defer`后面的`f.Close()`函数不会执行到
          : ...................

          err !=nil时,defer后面的还有执行的必要么。就是那个f.Close()
          --

          ※ 来源:·北邮人论坛 http://bbs.byr.cn·[FROM: 124.127.222.*]
            返回顶部
            lzj0218第5楼
            Snail
            等级
            用户
            文章
            442
            积分
            10897
            星座
            水瓶座
            发信人: lzj0218 (Snail), 信区: Golang
            标  题: Re: 请教两个Go的新手问题
            发信站: 北邮人论坛 (Sun May 20 12:42:24 2018), 站内

            em......确实,Open的时候出错的话返回的f是个nil,那没有执行f.Close()的必要了

            【 在 lsp 的大作中提到: 】
            :  
            : err !=nil时,defer后面的还有执行的必要么。就是那个f.Close()

            --

            ※ 来源:·北邮人论坛 http://bbs.byr.cn·[FROM: 120.52.147.*]
              返回顶部
              lizz第6楼
              シャノちゃん
              等级
              用户
              文章
              498
              积分
              26752
              发信人: lizz (シャノちゃん), 信区: Golang
              标  题: Re: 请教两个Go的新手问题
              发信站: 北邮人论坛 (Sun May 20 18:34:50 2018), 站内

              第一个问题,肯定是用f1

              Go里的结构体函数其实是语法糖,所以f.Close()相当于C里的fclose(f)。
              当os.Open()返回error时,f的值为nil,所以实际调用了flose(nil)。
              很多情况下,对nil进行对象操作是undefined behavior,任何后果都有可能发生。
              Go对fclose做了零值判断以避免崩溃,参见 https://golang.org/src/os/file_unix.go?s=5771:5799#L189

              如果你写过C,就会知道资源申请失败是不能进行释放操作,否则分分钟segmentation fault。


              第二个问题,Go不支持自动RAII,指针释放时不会有所谓的析构操作,所以不释放资源的话会造成fd泄露。
              如果想使用RAII的写法可以换一门语言,比如C++或Rust。





              --
              ※ 修改:·lizz 于 May 20 18:35:40 2018 修改本文·[FROM: 123.123.254.*]
              ※ 来源:·北邮人论坛 http://bbs.byr.cn·[FROM: 123.123.254.*]
                返回顶部
                Muggins第7楼
                莫泽
                等级
                用户
                文章
                66
                积分
                7978
                星座
                金牛座
                发信人: Muggins (莫泽), 信区: Golang
                标  题: Re: 请教两个Go的新手问题
                发信站: 北邮人论坛 (Fri May 25 16:06:33 2018), 站内

                第一个问题肯定用f2,至于楼上说的如果open失败,file为nil,close(nil)在golang中也是保护的,f.close()函数会返回error作为提示;
                第二个问题,golang触发垃圾回收机制时,当object被回收时文件会自动关闭,这个也是golang基本的保护,不然坑就太大了。
                --

                ※ 来源:·北邮人论坛 http://bbs.byr.cn·[FROM: 120.52.147.*]
                  返回顶部
                  lizz第8楼
                  シャノちゃん
                  等级
                  用户
                  文章
                  498
                  积分
                  26752
                  发信人: lizz (シャノちゃん), 信区: Golang
                  标  题: Re: 请教两个Go的新手问题
                  发信站: 北邮人论坛 (Sat Jun  2 19:50:40 2018), 站内

                  第一个问题肯定用f1,可以查看reddis的讨论,defer必须在错误检查之后调用

                  https://www.reddit.com/r/golang/comments/6gsjlf/dont_defer_close_on_writable_files/
                  https://joeshaw.org/dont-defer-close-on-writable-files/

                  --

                  ※ 来源:·北邮人论坛 http://bbs.byr.cn·[FROM: 42.3.20.*]
                    返回顶部
                    raaay0608第9楼
                    raaay0608
                    等级
                    用户
                    文章
                    386
                    积分
                    6748
                    星座
                    双子座
                    发信人: raaay0608 (raaay0608), 信区: Golang
                    标  题: Re: 请教两个Go的新手问题
                    发信站: 北邮人论坛 (Mon Jun 11 16:03:58 2018), 站内

                    前前后后研究了一阵子,来自问自答了。
                    
                    第一个问题,对于`os.File`来说无所谓,一方面`os.Open`在有`err != nil`的时候,`f`似乎都为`nil`,无需手动`f.Close()`,另一方面,官方对`os.File`的`Close()`实现中,会检查是不是nil,因此也不会崩。
                    
                    如果不是`os.File`,偶尔会比较恶心,目前用第三方包还没遇到过有`err`的同时`f`不为`nil`的情况,但是见过`Close()`没有检查nil导致panic的情况,具体情况写具体的东西吧...
                    我希望能在Close实现中检查nil,然后在写代码的时候尽可能“下一句就defer”,不然有时候处理err逻辑比较繁琐的时候还是很容易出错的。
                    
                    第二个问题,`runtime.SetFinalizer`可以为struct设置类似destructor的功能,当gc发生的时候执行指定操作,可以实现自动`Close()`,具体到实际应用中,已知`os.File`是自动关闭的(https://golang.org/src/os/file_unix.go#L132)
                    
                    并且已知,一些第三方库提供的东西,比如一些数据库驱动,也会在被gc的时候主动断开数据库连接等等。
                    尽管不是最佳实践,如果出于某些原因需要这样做(例如使用MultiReader、MultiWriter、TeeReader没有`Close()`等等),而且对等待GC导致的时延不敏感的话应该是可以不管的。

                    --

                    ※ 来源:·北邮人论坛 http://bbs.byr.cn·[FROM: 2001:da8:215:c5e7:e1db:8ea1:beec:*]
                      返回顶部
                      • 文章数:11 分页:
                        1. 1
                        2. 2
                        3. >>