【问题标题】:Closing an io.Reader that might be an os.Stdin关闭可能是 os.Stdin 的 io.Reader
【发布时间】:2021-09-27 02:38:12
【问题描述】:

如果给出了文件名,我试图将文件设置为输入,如果没有给出文件名,则使用标准输入。我会认为这是这样做的方法:

var input io.Reader
if filename == "" {
  input = os.Stdin
} else {
  input, err = os.Open(filename)
  if err != nil {
    log.Fatalf("failed to open file: %v", err)
  }
}

传递给input 的函数需要符合io.Reader 接口的东西,并且表现良好。也就是上面的作品……

在我想办法关闭input 之前,它一直有效。尽管 os.Stdin 和 os.Open 都返回了这两个东西(当然,关闭 stdin 可能没有多大意义,但它是无害的)。编译器不知道创建input 的两种方式都会给我一些实现Close() 的东西。所以我想知道有没有办法告诉编译器Close() 是为input 实现的。

【问题讨论】:

    标签: go


    【解决方案1】:

    使用io.ReadCloser 声明input 具有读取和关闭方法:

    var input io.ReadCloser
    if filename == "" {
      input = os.Stdin
    } else {
      input, err = os.Open(filename)
      if err != nil {
        log.Fatalf("failed to open file: %v", err)
      }
    }
    

    如果文件在从函数返回之前关闭,那么另一个选择是推迟文件关闭:

    var input io.Reader
    if filename == "" {
      input = os.Stdin
    } else {
      f, err := os.Open(filename)
      if err != nil {
        log.Fatalf("failed to open file: %v", err)
      }
      defer f.Close()
      input = f
    }
    

    【讨论】:

      【解决方案2】:

      在为其他人写我的问题并努力说明问题的过程中,我意识到用

      声明输入
      var input *os.File
      

      修复一切。

      在我开始写问题之前,我没有查看os.Stdin 的类型。因此,我根据将要使用它的函数所需的最通用接口声明了input

      【讨论】:

        【解决方案3】:

        检查io.Reader 是否实现Close 的方法是使用类型断言:

        if closer, ok:=reader.(io.Closer); ok {
           err:=closer.Close()
        }
        

        【讨论】:

        • 这告诉你io.Reader 是否实现io.Closer,但这并没有告诉你谁负责实际调用Close 方法——而io.Closer 留下了双重调用的行为到Close 明确未定义。所以这种类型断言充其量是脆弱和危险的。
        猜你喜欢
        • 2019-01-03
        • 2020-08-22
        • 2016-10-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-25
        • 1970-01-01
        相关资源
        最近更新 更多