删除打开文件的正确方法(Linux)

凭记忆复述一个坑,稍微带到 Linux 文件系统知识。时间久远,记忆可能存在差错。发现了错误请留言告知,感激不尽。

标题的中文断句上容易有歧义,重复一下英文:correct way to delete an opened file ,关键在 『打开了的文件』或者叫 『已经打开的文件』,怎么解释都比 opened 拗口。

(由于当时没有留下记录,文中 shell 输出均为写文章时 模拟重现,并非第一现场。)

阅读全文

配置 1.13+ 的 golang 环境

以前写过《配置 Golang 开发环境》(go < 1.13, win64)。然后 1.13 是一个重大变更,大到需要原有的依赖管理要做迁移的程度(《golang 1.13 - 依赖管理从 dep 到 mod 踩坑》)。

1.13 让原来的配置方式有了变化,撇开语言特性不谈,仅说和配置相关的,最大的变化,是 go module 的转正,和 GOPATH 和 vendor 的边缘化(1.13 仍然给你选择的余地,但是推荐选择 module,停用 GOPATH 和 vendor)。

那么如果你从 1.13 之后才刚刚开始接触 go, 那么前面两篇文章对你来说并不友好。

所以我找到了理由又水一篇。

阅读全文

golang 1.13 - 依赖管理从 dep 到 mod 踩坑

接触 golang 很晚,实际用来开发大概在 1.9 左右,所以我的主要印象是在 1.9 、 1.10 上的,依赖管理经过一些尝试之后,选择了 『官方』(后来实际被抛弃了)的 dep(《golang 依赖管理:glide 从入门到放弃》)。

后来 1.11、1.12 推出了 module (亦即 go mod 命令),考虑到尚不稳定又有切换成本,就继续留守在 vendor 目录上。

2019 年 9月终于 1.13 出来了,做了几个比较大的改动,同时 module 也终于转正,所以我终于下定决心迁移到 1.13,并改用 mod 做依赖管理。

阅读全文

golang 预置 json 包的值覆盖测试

json 作为一种可读性高、跨平台的序列化手段,常用在持久化和网络间传输。一般情况下,只需考虑是否按照作者的意图序列化和反序列化;反序列化的目标一般是一个 空白的对象,供写入得到的值。

但有一些特殊情况,还要考虑反序列化过程中,值的覆盖性:用到的字段非常多,给每个都赋值很麻烦,所以提供一套默认值(注意默认值不一定是 0 值),只要 json 中没有指定,就转而使用默认值。这在 jQuery 中只需要使用 $.extend(default, opts1, opts2...);而如果想递归合并,则只需要把 true 作为第一个参数。

阅读全文

golang-string 和 bytes 之间的 unsafe 转换

最近写一个 golang 的工具包时,涉及到反复在 string 和 []byte 之间来回转换。这给了我一个机会了解转换时底层发生的事情。

结论先行

  • string 和 []byte 互转都涉及底层数据复制;可以通过 unsafe 强制转换绕过复制提高性能。
  • string 类型的底层数组可能放在常量区(字面量初始化)也可能动态分配;无论哪一种,当以 string 类型出现时底层数据都是不可修改的(避免影响其他引用),string 的修改实际上是指向重新生成的底层数组。
  • 当以 []byte 类型出现时,可以修改具体某一个 byte 的值;不过如果是从指向常量区的 string 通过 unsafe 转换而来,尝试修改时会产生不可恢复的 runtime error。
  • 这也是为什么这个包叫 unsafe:绕过类型检查强行转换,绕过了底层数据复制,提高性能同时也失去了检查和复制的保护,需要调用方自行确认不会出错。
  • + 连接会复制内存,strings.Split() 直接在原串做切片…具体不同实现要以源码为准。
  • 即使 string 是动态分配的内容,也不建议修改对应的 []byte,可能会引起引用同一块内容的其他 string 的异常—— 除非你能确保没有别的地方引用它。
  • 实际调用中碰到了 对 A 串做 unsafe 转换,结果完全无关的 B 串出现切片时数组越界;A 串改为普通转换就好了。暂时没能找到原因,保险起见放弃使用 unsafe,改为用 json.RawMessage 多封装一层。本次研究权当学习了。

阅读全文