Objective
Goland is the JetBrains launch of the Golang IDE, in the inner stage I began to use, just out of time I also published in the blog post (see the next date is the end of 16).
At that time it was not very perfect, a lot of bugs. Accurate said also does not calculate the BUG, mainly is the grammar hints the various insufficiency, the reconstruction function is also very weak. Then I didn't write the go code for a while, until it was updated to the official version, and I almost took the opportunity to continue writing the go code. Although it is perfect, but it is still found a small but very obvious bug, but this bug just happened to cause me trouble, so I want to write a description.
About 0 values
When storage are allocated for a variable, either through a declaration or a call of new, or when a new value is created, E Ither through a composite literal or a call of make, and no explicit initialization are provided, the variable or value is Given a default value. Each element of such a variable or value was 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 do recursively, so for instance each element of the an array of structs would have it fields zeroed I F no value is specified.
The official documentation clearly states that the 0 value of Slice (slice) is nil, which is obvious in the absence of explicit initialization, which any Go developer should know.
For Goland, however, it is one thing to declare and initialize the null Slice and declare the Slice without initialization. Why do you say that? If you write the following two lines of code in Goland:
var sliceNoInit []stringsliceInit := []string{}
The second line of code has a wavy line to the right of the equals sign, suggesting that the notation can be Cleanup. If you press ALT as prompted by the IDE +enter then the second line of code will be re-formed:
You're not mistaken, Goland. Refactoring an initialized Slice to an uninitialized Slice ..... Goland that the former is a redundant notation. Indeed, most functions are the same for nil Slice and empty Slice, for example, they are 0 in length. But
Nil Slice has a length of 0, so the length of 0 can be converted to nil Slice
There is a problem with this consideration. What's wrong with that? Aren't they all two lengths of 0? Of course there is a problem, the note in the Len function is clearly written in such a sentence:
If V is nil and Len (v) is zero
What does that mean? That is, the Len function allows the parameter to be nil, but any type will return 0 if the parameter is nil. So nil Slice The length of zero is a non-prohibited argument, it should be said that the result of the call Len function is zero.
Therefore, an empty Slice after initialization is definitely not equivalent to nil Slice that is not initialized. Most directly, the opposite is the result of slice = = nil.
Trouble to bring
When using some JSON frameworks, nil Slice will be parsed to null instead of [], and if you have Web development experience you will know how serious it is to be a minor problem. And I happen to have this problem, and finally traced the reason is that I manually initialized the empty Slice is re-formed uninitialized nil Slice, directly resulting in this conversion to NULL results.
We use pseudo-code examples (no specific framework):
var list []stringif err,result := QueryAll();err== nil{ list = result.Rows}ToJson(map[string]interface{}{ "list": list,})
Did you see any problems? If Queryall returns an error, then the list is never initialized, and it is likely that it will be parsed to null instead of [] at the time of conversion.
The following code:
package mainimport ( "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{}}
If you initialize in the first way:
var list []string
The result is:
ss:{"list":null}, error:<nil>
Initialize in the second and third ways:*
list := make([]string, 0)list := []string{}
The result is:
ss:{"list":[]}, error:<nil>
If you want to write about this problem:
List: = []string{}
Then you will be goland alive to the above ... And then bring the wrong result.
Real details
In Goland's blog, there is an article about the value of Slice 0, which they think:
A nil slice is functionally equivalent to a zero-length slice, even though it points
The original is here: https://blog.golang.org/slices
The JSON method that causes Gin to convert nil Slice to NULL is due to JSON. That's what Marshal () does, which means that almost any place that involves JSON processing can be problematic because the Goland team thinks they are functionally equivalent.
Solutions
- Enter Settings-editor-inspections
- Expand Go-declaration Redundancy
- Remove the Empty slice declared via literal right-hand hook
To do this, you can turn off the Goland redundancy check for the directly initialized empty Slice.
But the interesting thing is that there is also a code to eliminate this hint, that is to use the Make function:
list := make([]string, 0)
Actually using make to create an empty Slice of length 0 and a direct initialization without inserting a value is equivalent ... But Goland does not use the initialization of the make function as a "redundant" notation.
Conclusion
This article is from: https://zhuanlan.zhihu.com/p/35777565
Just today encountered this Goland warning, by the way study record, invasion delete!