Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/vim/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Go 在重写变量上延迟文件关闭_Go - Fatal编程技术网

Go 在重写变量上延迟文件关闭

Go 在重写变量上延迟文件关闭,go,Go,我正在学习Go,所以我尝试编写一个应用程序,从JSON API获取一些数据并将其放入文件中。我编写了一个函数来检查我的文件是否存在,如果不存在,就创建它 func encureRefileExists(文件路径字符串){ f、 错误:=os.Open(存储文件) 延迟函数(){ 错误:=f.Close() 如果错误!=零{ fmt.Printf(“无法关闭文件%q,错误:%q”,文件路径,错误) 返回 } fmt.Printf(“文件%q已关闭”,文件路径) }() 如果错误!=零{ 如果os.

我正在学习Go,所以我尝试编写一个应用程序,从JSON API获取一些数据并将其放入文件中。我编写了一个函数来检查我的文件是否存在,如果不存在,就创建它

func encureRefileExists(文件路径字符串){
f、 错误:=os.Open(存储文件)
延迟函数(){
错误:=f.Close()
如果错误!=零{
fmt.Printf(“无法关闭文件%q,错误:%q”,文件路径,错误)
返回
}
fmt.Printf(“文件%q已关闭”,文件路径)
}()
如果错误!=零{
如果os.IsNotExist(错误){
f、 err=os.Create(存储文件)
如果错误!=零{
恐慌(错误)
}
返回
}
恐慌(错误)
}
}
我的考虑是:

  • 这是正确的做法吗
  • 如果文件未打开(通过
    打开
    创建
    ,…),则调用
    延迟f.Close()
    是一件坏事,是否应该仅在错误检查后调用它
  • 这与前面的问题有点相关,假设从
    os.Open
    调用中总结该文件不需要关闭,因为返回了错误,不需要将
    os.Create
    的结果分配给新变量并单独关闭,对吗
  • f.Close()
    失败时该怎么办,除了放置一些日志或忽略它之外,还有什么要做的吗

  • 我想说你的方法有很多“错误”

    首先,如果一个函数被定义为返回一个错误和其他值,那么您几乎应该首先检查错误,只有在没有错误的情况下才尝试使用其他值。
    一个众所周知(但罕见)的例外是
    io.Reader
    io.Writer
    接口的方法,该接口可能会返回非零的读/写字节数和非
    nil
    错误

    虽然延迟调用不会立即使用分配给
    f
    的值,但如果调用
    os.Open
    失败,因此返回非
    nil
    错误,则分配给
    f
    的值实际上未定义。Go不是C,要让它在真正未初始化的内存上运行,必须进行大量操作(并使用
    不安全的
    ),但最重要的事实是,大多数具有多个返回值的函数,其中一个是
    error
    ,不要记录任何状态如果
    错误
    不是
    nil
    ,其余的值将是
    特别是,
    os.File
    可以自由返回任何值作为第一个返回值,而第二个返回值是非
    nil
    错误

    嗯,细心的程序员通常不会做愚蠢的事情,
    os.Open
    实际上返回
    nil
    作为第一个返回值,而第二个
    error
    不是
    nil

    但是,想想如果对
    os.Open
    的调用失败会发生什么:变量
    f
    被赋值为
    nil
    ,然后对该变量上关闭的函数literal的延迟调用将尝试调用
    Open
    nil

    同样,在指针接收器上定义的一些方法知道当它们的接收器是
    nil
    时该做什么,但是
    Open
    不是它们中的一个,它只会在尝试取消引用
    nil
    指针时爆炸

    是的,您似乎通过后续调用
    os.Create
    来“补偿”这一点,这是不允许通过使用
    panic
    失败的,但这只会创建复杂的代码。我认为您提出这个解决方案是为了不编写两个
    defer
    块,一个用于成功的
    os.Open
    ,另一个用于成功的
    os.Create
    ,但如果我是您,我只编写了一个简单的“Open或Create”将返回与
    os.Open
    os.Create
    do相同值的帮助程序。信不信由你,Go已经有一本书了;-)

    因此,大多数情况下正确的使用模式是

    f,err:=os.Open(…)
    如果出错!=零{
    //处理错误
    返回。。。
    }
    //此时,已知f处于良好状态
    延迟函数(){
    错误:=f.Close()
    // ...
    }()
    
    其次,不需要采用先尝试打开,然后在不存在的情况下创建的方法:
    os.open
    os.create
    可以被看作是通用接口的简化接口(它非常接近于。
    使用
    O_CREATE
    标志,如果文件不存在,该函数将自动创建该文件,并且作为一个额外的功能,该功能会自动创建与检查相关的文件(虽然您的方法与文件系统有着天然的竞争:在尝试打开文件和尝试创建文件之间,其他一些进程可能会创建文件,从而导致第二次调用失败)

    关于你的最后一个问题,答案是“视情况而定”:

    • 如果打开一个文件进行读取,并且您已成功读取该文件中的所有(必需)数据,则关闭该文件时出现错误并不意味着您丢失了任何内容,实际上不太可能发生。在大多数情况下,将其记录为警告并继续是可以的
    • 如果某个文件是为写入而打开的,未能关闭它可能意味着在调用
      Close
      之前,您可能丢失了写入该文件的部分内容。 调用
      Close
      失败的一个常见示例是驻留在网络文件系统(如NFS或CIFS)上的文件。
      具体应该采用什么策略在很大程度上取决于执行该操作的流程的性质:例如,如果您正在编写电子邮件服务器,则无法存储消息应导致放弃并正确地将问题传达给发送客户端;如果您正在编写交互式应用程序,则可能会询问用户至少,允许他们重试或更改文件的位置,然后重试或其他操作

    见否。是。视情况而定。