Difference between []Foo(nil) and []Foo{} in Go - arrays

I'm new to Go and would like to know the difference between []Foo(nil) and []Foo{}.
(I'm using this in my tests, where I want to specify that when my function errors, it should return nil, err. The go linter complains when I use nil or []Foo{}, but works when I use []Foo(nil).)
What I've tried
I had a look at the Go docs and on SO and found Struct stuff about Foo{} but not []Foo(nil).
When I use []Foo{}, the test failure outputs:
expected: []Foo{}
actual : []Foo(nil)
Fmt outputs for []Foo(nil) and []Foo{} are the same:
fmt.Println([]Foo(nil)) // []
fmt.Println([]Foo(){}) // []
fmt.Printf([]Foo(nil)) // []Foo
fmt.Printf([]Foo(){}) // []Foo
I noticed that if I write just Foo(nil) (without the []) then the linter complains about cannot convert nil to type Foo.
So my only guess is that []Foo(nil) invokes some type coercion. Can anyone help me out?

The expression []Foo(nil) is a conversion. It converts the untyped nil to a nil slice of type []Foo.
The expression []Foo{} is a composite literal that returns a empty slice. It's empty because no elements are listed between the {}.
This might help explain the difference:
fmt.Println([]Foo(nil) == nil) // prints true
fmt.Println([]Foo{} == nil) // prints false
A nil slice does not have a backing array. An empty slice has a backing array with length 0.
What's confusing is that the fmt package can output the same data for empty slices and nil slices.
If the distinction between a nil slice and empty slice is not important in your tests, then test with len(s) == 0. This expression evaluates to true for both nil slices and empty slices.

Related

Implement Scan interface to read json array into map

I am fetching a JSON array from PostgreSQL, and I would like to read it into a map. I am able to Unmarshal the values into a []string slice, but what I actually want is a map[string]bool.
I've written a custom type for the column with a Scan interface that converts the JSON array into a slice of strings first, then reads each string into the custom map type as keys.
type custMap map[string]bool
func (m *custMap) Scan(src interface{}) error {
b, ok := src.([]byte)
if !ok {
return error(errors.New("Error Scanning Array"))
}
s := make([]string, 0)
json.Unmarshal(b, &s)
for _, v := range s {
(*m)[v] = true
}
return nil
}
type data struct {
vals custMap `json: "vals"`
}
The query I am trying to scan returns a row with a column vals which is a JSON array: ["some", "arr", "vals"], where the custom type is used like so:
var d models.data
sqlDB.QueryRow().Scan(&d.vals)
My expected output is a struct with the following shape
{ vals: map[string]bool { "some": true, "arr": true, "vals": true }
This compiles fine, but my code panics with "assignment to entry in nil map"
How can I fix my Scan function? Is it even possible to do this with a map type?
You are calling your method Scan of type *custMap on a unitialised map. Initialize d.vals either like
d.vals = custMap{}
or
d.vals = make(custMap)
Other answers already provide an explanation.
The Go Programming Language Specification
Map types
A map is an unordered group of elements of one type, called the
element type, indexed by a set of unique keys of another type, called
the key type. The value of an uninitialized map is nil.
A new, empty map value is made using the built-in function make, which
takes the map type and an optional capacity hint as arguments:
make(map[string]int)
make(map[string]int, 100)
The initial capacity does not bound its size: maps grow to accommodate
the number of items stored in them, with the exception of nil maps. A
nil map is equivalent to an empty map except that no elements may be
added.
I don't see a make to initialize your map: "A nil map is equivalent to an empty map except that no elements may be added."

swift os x array binary operator error compare with nil != if statement

I have declared an array of an array of tuples:
var graphDetailsArray: [Array<(graphType: String, columnLabel: String, columnColor: NSColor, columnHeight: CGFloat, columnNumber: Int)>] = []
a little later on in the function I check this array for nil before activating some code:
if graphDetailsArray != nil { //some code here
This is throwing up an error at build time:
Binary operator '!=' cannot be applied to type Array<(graphType:
String, columnLabel: String, columnColor: NSColor, columnHeight:
CGFloat, columnNumber: Int)> and nil.
I have a tried a range of different syntaxes and can not get this to work.
Any assistance would be appreciated. How do I check for an empty array?
Is using "graphDetails.isEmpty" the same as checking for nil??
Your array is an array, not an optional array. While an optional array could be nil, a non-optional array in Swift can never, ever be nil. Therefore, it doesn't even support an if-statement that would compare it to nil.
Replace
graphDetailsArray != nil
with
true
or remove the if-statement completely.
isEmpty is something totally different. An array could have 0 elements, 1 element, 2 elements etc. isEmpty returns true if your array has 0 elements. Which is totally different from an array being nil.

Correct way to initialize empty slice

To declare an empty slice, with a non-fixed size,
is it better to do:
mySlice1 := make([]int, 0)
or:
mySlice2 := []int{}
Just wondering which one is the correct way.
The two alternative you gave are semantically identical, but using make([]int, 0) will result in an internal call to runtime.makeslice (Go 1.16).
You also have the option to leave it with a nil value:
var myslice []int
As written in the Golang.org blog:
a nil slice is functionally equivalent to a zero-length slice, even though it points to nothing. It has length zero and can be appended to, with allocation.
A nil slice will however json.Marshal() into "null" whereas an empty slice will marshal into "[]", as pointed out by #farwayer.
None of the above options will cause any allocation, as pointed out by #ArmanOrdookhani.
They are equivalent. See this code:
mySlice1 := make([]int, 0)
mySlice2 := []int{}
fmt.Println("mySlice1", cap(mySlice1))
fmt.Println("mySlice2", cap(mySlice2))
Output:
mySlice1 0
mySlice2 0
Both slices have 0 capacity which implies both slices have 0 length (cannot be greater than the capacity) which implies both slices have no elements. This means the 2 slices are identical in every aspect.
See similar questions:
What is the point of having nil slice and empty slice in golang?
nil slices vs non-nil slices vs empty slices in Go language
As an addition to #ANisus' answer...
below is some information from the "Go in action" book, which I think is worth mentioning:
Difference between nil & empty slices
If we think of a slice like this:
[pointer] [length] [capacity]
then:
nil slice: [nil][0][0]
empty slice: [addr][0][0] // points to an address
nil slice
They’re useful when you want to represent a slice that doesn’t exist, such as when an exception occurs in a function that returns a slice.
// Create a nil slice of integers.
var slice []int
empty slice
Empty slices are useful when you want to represent an empty collection, such as when a database query returns zero results.
// Use make to create an empty slice of integers.
slice := make([]int, 0)
// Use a slice literal to create an empty slice of integers.
slice := []int{}
Regardless of whether you’re using a nil slice or an empty slice, the built-in functions append, len, and cap work the same.
Go playground example:
package main
import (
"fmt"
)
func main() {
var nil_slice []int
var empty_slice = []int{}
fmt.Println(nil_slice == nil, len(nil_slice), cap(nil_slice))
fmt.Println(empty_slice == nil, len(empty_slice), cap(empty_slice))
}
prints:
true 0 0
false 0 0
Empty slice and nil slice are initialized differently in Go:
var nilSlice []int
emptySlice1 := make([]int, 0)
emptySlice2 := []int{}
fmt.Println(nilSlice == nil) // true
fmt.Println(emptySlice1 == nil) // false
fmt.Println(emptySlice2 == nil) // false
As for all three slices, len and cap are 0.
In addition to #ANisus' answer
When using the official Go MongoDb Driver, a nil slice will also marshal into "null" whereas an empty slice will marshal into "[]".
When using using the community supported MGO driver, both nil and empty slices will be marshalled into "[]".
Reference: https://jira.mongodb.org/browse/GODRIVER-971

How to write func for the generic parameter in golang

I am trying to write a function Map, so that it can handle all the types of array.
// Interface to specify generic type of array.
type Iterable interface {
}
func main() {
list_1 := []int{1, 2, 3, 4}
list_2 := []uint8{'a', 'b', 'c', 'd'}
Map(list_1)
Map(list_2)
}
// This function prints the every element for
// all []types of array.
func Map(list Iterable) {
for _, value := range list {
fmt.Print(value)
}
}
But it throws the compile time error.
19: cannot range over list (type Iterable)
The error is correct because range require array, pointer to an array, slice, string, map, or channel permitting receive operations and here type is Iterable. I think problem that I am facing is, conversion of the argument type Iterable to array type. Please suggest, how could I use my function to handle generic array.
As Rob Pike mentions in this thread
Is it possible to express "any map", "any array" or "any slice" in a Go type switch?
No. The static types must be exact.
The empty interface is really a type, not a wildcard.
You only could iterate over a list of a specific type, like an interface with known functions.
You can see an example with "Can we write a generic array/slice deduplication in go?"
Even using reflection, to pass a slice as an interface{} would be, as this thread shows, error-prone (see this example).
Update Nov. 2021, 7 years later: CL 363434, for Go 1.18 (Q1 2022) actually introduces functions useful with slices of any type, using generics.
// Package slices defines various functions useful with slices of any type.
// Unless otherwise specified, these functions all apply to the elements
// of a slice at index 0 <= i < len(s).
package slices
import "golang.org/x/exp/constraints"
// Equal reports whether two slices are equal: the same length and all
// elements equal. If the lengths are different, Equal returns false.
// Otherwise, the elements are compared in index order, and the
// comparison stops at the first unequal pair.
// Floating point NaNs are not considered equal.
func Equal[T comparable](s1, s2 []T) bool {
if len(s1) != len(s2) {
return false
}
for i, v1 := range s1 {
v2 := s2[i]
if v1 != v2 {
return false
}
}
return true
}
Note that issue 50792 and CL 382834 show that:
We left constraints behind in the standard library because we believed it was fundamental to using generics, but in practice that hasn't proven to be the case.
In particular, most code uses any or comparable.
If those are the only common constraints, maybe we don't need the package.
Or if constraints.Ordered is the only other commonly used constraint, maybe that should be a predeclared identifier next to any and comparable.
Hence import "golang.org/x/exp/constraints" instead of import "constraints".
Your definition of Map is some unсomplete. Usual way to declare it would have mapper method.
Your example can be implemented at least this way
package main
import "fmt"
// Interface to specify something thet can be mapped.
type Mapable interface {
}
func main() {
list_1 := []int{1, 2, 3, 4}
list_2 := []string{"a", "b", "c", "d"}
Map(print, list_1)
Map(print, list_2)
}
func print(value Mapable){
fmt.Print(value)
}
// This function maps the every element for
// all []types of array.
func Map(mapper func(Mapable), list ... Mapable) {
for _, value := range list {
mapper(value)
}
}
It works. Need to say it's a bit of untyped. Because no, Go has not 'generics' in Hindley-Milner sence

Swift: optional array count

In Objective-C, if I had the following property:
#property (strong, nonatomic) NSArray * myArray;
A method to return a number of objects in myArray would look like:
- (NSInteger) numberOfObjectsInMyArray
{
return [self.myArray count];
}
This would return either the number of objects in the array, or 0 if myArray == nil;
The best equivalent I can think of for doing this in Swift is:
var myArray: Array<String>?
func numberOfObjectsInMyArray() -> Int
{
return myArray ? myArray!.count : 0
}
So checking the optional array contains a value, and if so unwrap the array and return that value, otherwise return 0.
Is this the correct way to do this? Or is there something simpler?
Try using the nil coalescing operator.
According to the Apple Documentation:
The nil coalescing operator (a ?? b) unwraps an optional a if it contains a value, or returns a default value b if a is nil.
So your function could look like this:
func numberOfObjectsInMyArray() -> Int {
return (myArray?.count ?? 0)
}
I agree with others that this could be a bad idea for a number of reasons (like making it look like there is an array with a count of "0" when there isn't actually an array at all) but hey, even bad ideas need an implementation.
EDIT:
So I'm adding this because two minutes after I posted this answer, I came across a reason for doing exactly what the author wants to do.
I am implementing the NSOutlineViewDataSource protocol in Swift. One of the functions required by the protocol is:
optional func outlineView(_ outlineView: NSOutlineView,
numberOfChildrenOfItem item: AnyObject?) -> Int
That function requires that you return the number of children of the item parameter. In my code, if the item has any children, they will be stored in an array, var children: [Person]?
I don't initialize that array until I actually add a child to the array.
In other words, at the time that I am providing data to the NSOutlineView, children could be nil or it could be populated, or it could have once been populated but subsequently had all objects removed from it, in which case it won't be nil but it's count will be 0. NSOutlineView doesn't care if children is nil - all it wants to know is how many rows it will need to display the item's children.
So, it makes perfect sense in this situation to return 0 if children is nil. The only reason for calling the function is to determine how many rows NSOutlineView will need. It doesn't care whether the answer is 0 because children is nil or because it is empty.
return (children?.count ?? 0) will do what I need. If children is nil it will return 0. Otherwise it will return count. Perfect!
That looks like the simpler way.
The Objective-C code is shorter only because nil is also a form of 0, being a C-based language.
Since swift is strongly typed you don't have such a shorthand. In this specific case it requires a little more effort, but in general it saves you most of the headaches caused by loose typing.
Concerning the specific case, is there a reason for making the array optional in the first place? You could just have an empty array. Something like this might work for you:
var myArray: Array<String> = []
func numberOfObjectsInMyArray() -> Int {
return myArray.count
}
(Source for this information)
How about using optional for return value?
var myArray: Array<String>?
func numberOfObjectsInMyArray() -> Int? {
return myArray?.count
}
I think that this way is safer.
(Source for this information)

Resources