Go 语言 IDE GoLand 的 BUG

前言

GoLand 是 Jetbrains 推出的 Golang IDE,在内侧阶段我就开始使用了,刚出的时候我还在博客中发表过文章(看了下日期是 16 年年底)。

那时候它还不是很完善,BUG 很多。准确的说也不算 BUG,主要是语法提示上的各种不足,重构功能也很弱。后来我有一段时间没有写 Go 代码,直到它更新为正式版我才差不多又抽出机会继续写 Go 代码了。虽然它已经很完善了,但还是发现它的一个很小但又很明显的 BUG,不过这个 BUG 却恰好给我造成了麻烦,所以我才想发文描述一下。

有关零值

When storage is allocated for a variable, either through a declaration or a call of new, or when a new value is created, either through a composite literal or a call of make, and no explicit initialization is provided, the variable or value is given a default value. Each element of such a variable or value is set to the zero value for its type: false for booleans, 0 for numeric types, “” for strings, and nil for pointers, functions, interfaces, slices, channels, and maps. This initialization is done recursively, so for instance each element of an array of structs will have its fields zeroed if no value is specified.

官方文档中明确指出,Slice(切片)的零值是 nil,在没有明确初始化的情况下这是显而易见的,任何 Go 开发者应该都知道才对。

但是对于 GoLand 而言,声明并直接初始化的空 Slice 和声明不初始化 Slice 是一回事。为什么这么说呢?如果你在 GoLand 中写入以下两句代码:

var sliceNoInit []string
sliceInit := []string{}

第二行代码的等号右边会有波浪线,提示这种写法可以被 Cleanup。如果你根据 IDE 提示按 Alt +Enter 那么第二行代码会被重构成:

var sliceInit []string 

你没有看错,GoLand 将一个初始化过的 Slice 重构为了未初始化的的 Slice…… GoLand 认为前者是冗余的写法。的确,大部分函数对于 nil Slice 和 empty Slice 而言,都是一样的,例如它们的长度都是 0。不过

nil Slice 的长度为 0,所以长度为 0 的都可以转变 nil Slice

这样考虑就有问题了。这有什么问题吗?它们两个长度不都是零么?当然有问题,在 len 函数的注释清晰的写了这么一句话:

if v is nil, len(v) is zero
这是什么意思呢?就是说 len 函数允许参数为 nil,但只要参数为 nil 不管任何类型都会返回 0。所以 nil Slice 的长度为零是一种不严禁的说法,应该说调用 len 函数的结果为零。

所以,初始化后空的 Slice 是绝对不等同于没有初始化的 nil Slice 的。最直接的,它们对 slice == nil 的结果就相反。

带来的麻烦

在使用某些 JSON 框架的时候,nil Slice 会被解析为 null 而不是 [],如果你有 web 开发经验就知道这是个多么严重的小问题了。而我恰好就是遇到这个问题了,最后追查原因原来是我手动初始化的空 Slice 被重构成了未初始化 nil Slice,直接导致了这个转换为 null 的结果。

我们用伪代码举例(不涉及具体框架):

var list []string
if err,result := QueryAll();err== nil{
    list = result.Rows
}
ToJson(map[string]interface{}{
    "list": list,
})

有没有看出什么问题?如果 QueryAll 返回错误的话,那么 list 永远不会被初始化,则很有可能在转换时被解析为 null 而不是 []。

如下代码:

package main

import (
    "encoding/json"
    "github.com/pkg/errors"
    "fmt"
)

type result struct {
    Rows []string
    Columes []string
}

func main() {
    //1、var list []string

    //2、list := make([]string, 0)
    list := make([]string, 0)

    //3、list := []string{}

    if err, result := QueryAll(); err == nil {
        list = result.Rows
    }
    ss, err := json.Marshal(map[string]interface{}{
        "list": list,
    })

    fmt.Printf("ss:%s, error:%v", string(ss), err)
}

func QueryAll() (error, result) {
    return errors.New("error"), result{}
}


如果用第一种方式初始化:

var list []string

结果为:

ss:{"list":null}, error:<nil>


用第二种和第三种方式初始化:*

list := make([]string, 0)
list := []string{}

结果为:

ss:{"list":[]}, error:<nil>


如果你想这么写解决这个弊端:

list := []string{}

那么你会被 GoLand 活活纠正成上面那样…… 然后带来错误的结果。

真实细节

在 GoLand 的博客中有一篇文章提到了关于 Slice 的零值,他们是这么认为的:

a nil slice is functionally equivalent to a zero-length slice, even though it points to nothing

原文在这里:https://blog.golang.org/slices

而造成 gin 的 JSON 方法将 nil Slice 转换 null 的原因是 json.Marshal() 就是这么处理的,也就是说几乎任何涉及到 JSON 处理的地方都有可能因为 GoLand 团队认为二者在功能上完全等价而造成问题。

解决办法

  • 进入 Settings -> Editor - Inspections
  • 展开 Go - Declaration redundancy
  • 将 Empty slice declared via literal 右边的勾去掉
    这么做可以关掉 GoLand 对直接初始化的空 Slice 的冗余检查。

不过有意思的是还有一种以代码的方式杜绝这种提示,那就是使用 make 函数:

list := make([]string, 0)

实际上使用 make 创建一个长度为 0 的 empty Slice 和不插入一个值的直接初始化这两者才是等价的…… 但是 GoLand 却不会将 make 函数这种初始化方式算做“冗余”写法。

结束语

本文来自知乎:https://zhuanlan.zhihu.com/p/35777565
刚好今天遇到这个goland警告,顺便学习记录下,侵删!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容