What is the difference between := and = in Go? - go

I am new to Go programming language.
I noticed something strange in Go: I thought that it used := and substitutes = in Python, but when I use = in Go it is also works.
What is the difference between := and =?

= is assignment. more about assignment in Go: Assignments
The subtle difference between = and := is when = used in variable declarations.
General form of variable declaration in Go is:
var name type = expression
the above declaration creates a variable of a particular type, attaches a name to it, and sets its initial value. Either the type or the = expression can be omitted, but not both.
For example:
var x int = 1
var a int
var b, c, d = 3.14, "stackoverflow", true
:= is called short variable declaration which takes form
name := expression
and the type of name is determined by the type of expression
Note that: := is a declaration, whereas = is an assignment
So, a short variable declaration must declare at least one new variable. which means a short variable declaration doesn't necessarily declare all the variables on its left-hand side, when some of them were already declared in the same lexical block, then := acts like an assignment to those variables
For example:
r := foo() // ok, declare a new variable r
r, m := bar() // ok, declare a new variable m and assign r a new value
r, m := bar2() //compile error: no new variables
Besides, := may appear only inside functions. In some contexts such as the initializers for "if", "for", or "switch" statements, they can be used to declare local temporary variables.
More info:
variable declarations
short variable declarations

= is just assignment
:= is declare-and-initialize construct for new vars (at least one new var) inside the function block (not global):
var u1 uint32 //declare a variable and init with 0
u1 = 32 //assign its value
var u2 uint32 = 32 //declare a variable and assign its value at once
//declare a new variable with defining data type:
u3 := uint32(32) //inside the function block this is equal to: var u3 uint32 = 32
fmt.Println(u1, u2, u3) //32 32 32
//u3 := 20//err: no new variables on left side of :=
u3 = 20
fmt.Println(u1, u2, u3) //32 32 20
u3, str4 := 100, "str" // at least one new var
fmt.Println(u1, u2, u3, str4) //32 32 100 str

:= is the "short declaration form" for declaring and initializing variables. It does type inference on the value that you are assigning to set the variable's type.
If you attempt to assign with the short declaration form to the same variable in the same scope, the compiler will throw an error.
Be on the lookout for the short declaration form "shadowing" the same variable in an enclosing scope (especially with errors)
= requires the var keyword when declaring a variable and the variable's type explicitly following the variable name. You can actually leave the = off the declaration since Go has a initial value for all types (strings are initialized as "", ints are 0, slices are empty slices). It can also be used for reassignment with just a value, ie
var s string = "a string" // declared and initialized to "a string"
s = "something else" // value is reassigned
var n int // declared and initialized to 0
n = 3

Inside a function, the := short assignment statement can be used in place of a var declaration with implicit type.
for example:
package main
import "fmt"
func main() {
var i, j int = 1, 2
k := 3
c, python, java := true, false, "no!"
fmt.Println(i, j, k, c, python, java)
}
NOTICE: the variable declared with := can only be used inside the function block.

I took time to figure out a mistake I made that could help you to clarify the difference between := and =.
Consider the following code:
type mystruct struct {
a int
arr []int
}
func main() {
m := mystruct{}
m.arr := make([]int, 5) //compilation error because m.arr is already declared.
m.arr = make([]int, 5) //compiles
}

= is used as statically typed.
:= is used as dynamically typed.
example:
var a = 30 # statically typed and is a compile time check
b := 40 # dynamically checked.

Note the difference in := and = in range clauses as well. The following examples are adapted from the spec.
The iteration variables may be declared by the "range" clause using a form of short variable declaration (:=). In this case their types are set to the types of the respective iteration values and their scope is the block of the "for" statement; they are re-used in each iteration. If the iteration variables are declared outside the "for" statement, after execution their values will be those of the last iteration.
= range ...:
i := 2
x = []int{3, 5, 7}
for i, x[i] = range x { // i,x[2] = 0,x[0]
break
}
// now i == 0 and x == []int{3, 5, 3}
var (key string; val interface{})
m := map[string]int{"mon":0, "tue":1, "wed":2, "thu":3, "fri":4, "sat":5, "sun":6}
for key, val = range m {
h(key, val)
}
// key == last map key encountered in iteration (note order of map iteration is random)
// val == map[key]
:= range ...:
var a [10]string
for i, s := range a {
// type of i is int, type of s is string
// s == a[i]
someFunction(i, s)
}
// i and s are no longer accessible here.
for i := range a { // roughly equivalent to `for i := 0; i < len(a); i++`
someFunction(i, a[i])
}
for _, s := range a {
anotherFunc(s)
}
// Above is roughly equivalent to:
{
var s string
for i := 0; i < len(a); i++ {
s = a[i]
anotherFunc(s)
}
}
// s not accessible here

The most verbose way to declare a variable in Go uses the var keyword, an explicit type, and an assignment.
var x int = 10
Go also supports a short declaration format. When you are within a function, you can
use the := operator to replace a var declaration that uses type inference.
var x = 10
x := 10
There is one limitation on :=. If you are declaring a variable at package level, you
must use var because := is not legal outside of functions.
There are some situations within functions where you should avoid :=
When initializing a variable to its zero value, use var x int. This makes it clear
that the zero value is intended.
When assigning an untyped constant or a literal to a variable and the default type
for the constant or literal isn’t the type you want for the variable, use the long var
form with the type specified. While it is legal to use a type conversion to specify
the type of the value and use := to write x := byte(20), it is idiomatic to write
var x byte = 20.
Because := allows you to assign to both new and existing variables, it sometimes
creates new variables when you think you are reusing existing ones. In those situations, explicitly declare all
of your new variables with var to make it clear which variables are new, and then
use the assignment operator (=) to assign values to both new and old variables.
While var and := allow you to declare multiple variables on the same line, only use
this style when assigning multiple values returned from a function or the comma ok
idiom.
Learning Go Jon Bondner

Related

Go - The difference between var and func to define a function

I'm coming from an Scala background, and in Scala, you could define functions both as a single value, or an actual function, for instance:
val inc1: Int => Int = _ + 1 // single FUNCTION value
def inc2(x: Int): Int = x + 1 // normal function definition
// in this case "inc1 eq inc1" is true, since this is a single instance
// but "inc2 eq inc2" is false
And these 2 have some differences (i.e., size allocation, first one is a single instance, while the other one returns an instance each time it is invoked, ...), so based on the use case, we could kind of reason which one to use. Now I'm new to golang, and wanted to know if the below 2 function definitions (correct me if I'm wrong with the phrase) differ in Golang, and if so, what are differences?
var inc1 = func(x int) int { return x + 1 }
func inc2(x int) int { return x + 1 }
Thanks in advance!
Scala borrows a lot from functional programming. Go does not.
(If you've used multiple other programming languages, you should definitely read the Go specification. It's not very long as Go is not a very large language, although the new generics definitely complicate things a bit.)
In Go, the func keyword introduces a function definition or function type, with the details being context-dependent. The var keyword introduces a variable declaration.1 So:
func inc2(x int) int { return x + 1 }
defines a function, inc2, whose code is as shown. But:
var inc1 = // ...
declares and then initializes a variable, inc1. The type and initial value of the variable are determined by the commented-out section, so:
var inc1 = func(x int) int { return x + 1 }
defines a function (with no name) whose code is as shown. That function is then assigned to the variable as its initial value, so that the implied type of the variable is func (int) int or function taking one argument of type int and returning one value of type int.
Having created a variable, you can now either call the function currently stored in that variable:
func callit(arg int) {
result := inc1(arg)
// ... do something with the result ...
}
Or you can assign a new value into the variable, e.g.:
func overwrite() {
inc1 = func(a int) int { return a * 2 } // name `inc1` is now misleading
}
Because inc2 is a function, you can't re-assign a new value to it: it's just a function, not a variable.
1Note that a variable declaration with an initialization can use the "short declaration" form:
func f() {
v := 3
// ...
}
where we leave out the type and just say "use the type of the expression to figure out the type of the declaration". This declares and initializes the variable. Short declarations can only appear in block scope, so these must be inside some function. Other than omitting the var keyword they do nothing that you couldn't do by including the var keyword, or sometimes multiple var keywords:
result, err := doit()
might require:
var result someType
var err error
result, err = doit()
when written without using the short-declaration form.

Short format var declaration in for loop

Please see the code below. (A) is not ok in Go and I understand why. But why is (B) ok in Go ?
(A) is not ok: because re-definition of a (no new var in LHS of := )
(B) should be an error too: because re-definition of r (no new var in LHS of := ) as the loop will execute r := with each iteration while r is still in scope.
package main
import "fmt"
func main() {
a := make([]byte, 10)
fmt.Println(a)
a := make([]byte, 10) //not ok and I understand why : (A)
fmt.Println(a)
for i := 0; i < 5; i++ {
r := make([]byte, 10) //ok, but why is this ok? : (B)
fmt.Println(r)
}
}
The key idea behind the short format declaration is that it has to define at least one new variable in the current block. So it fails in the first case because it is attempting to redefine a in the current block without introducing any new variables. The second block works, because r is a new variable declared in the current block.
As describe in go doc specifications about Short_variable_declarations, it is temporary for the scope.
Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block (or the parameter lists if the block is the function body) with the same type, and at least one of the non-blank variables is new. As a consequence, redeclaration can only appear in a multi-variable short declaration. Redeclaration does not introduce a new variable; it just assigns a new value to the original.
Short variable declarations may appear only inside functions. In some contexts such as the initializers for "if", "for", or "switch" statements, they can be used to declare local temporary variables.
You can not redeclare same variable with short variable declaration in same scope.
a, a := 1, 2 // illegal: double declaration of a or no new variable if a was declared elsewhere
In your case, r is in loop scope and each iteration r is a new variable. Because for loop repeats execution of a block.
A "for" statement specifies repeated execution of a block
If you need to clarify this please run below loop code and see r's memory addresses for each iterations. It will print five different addresses.
for i := 0; i < 5; i++ {
r := make([]byte, 10) //ok, but why is this ok? : (B)
fmt.Printf("%p\n",r)
}

Question about Map, String Pointers and Closure

I discovered a bug with my code when I was trying to convert map[string]string to map[string]*string (conversion is required by the API that I was consuming).
The Problem
In my first method, I tried to iterate over each entry in the source map, aMap and convert the string value of each entry into a string pointer and assign this pointer value to the destination map, bMap sharing the same key as aMap. I initially expected the dereferenced value held in bMap to be the same as aMap under the same key. However, it turned out that the deferenced value of bMap does not share the same value with aMap under the same key.
My questions would be:
Why does this problem happen?
I was able to resolve the issue using the second method, by first defining a function that receives a string and returns a pointer, that way I was able to correctly return the deferenced value to share the same value as aMap under the same key. Why does this method work?
Also, just curious, why is &(*v) a syntax error in Go? I also tried declaring a dummy variable val := *v, and assigning it to bMap using bMap[key] = &val but to no avail. The error said invalid indirect of v (type string)
Source Code
https://play.golang.org/p/ZG7XS2vJx0y
func main() {
aMap := make(map[string]string)
aMap["foo"] = "bar"
aMap["bar"] = "baz"
aMap["baz"] = "foo"
bMap := make(map[string]*string)
for k, v := range(aMap){
bMap[k] = &v
}
// first method
fmt.Println("1st method, map[string]*string, bMap")
for k, v := range(bMap){
fmt.Printf("bMap[%s] = %s / %s, aMap[%s] = %s\n",
k, *bMap[k], *v, k, aMap[k])
}
pString := func(v string) *string{ return &v }
for k, v := range(aMap){
bMap[k] = pString(v)
}
// second method
fmt.Println("2nd method, map[string]*string, bMap")
for k, v := range(bMap){
fmt.Printf("bMap[%s] = %s / %s, aMap[%s] = %s\n",
k, *bMap[k], *v, k, aMap[k])
}
// expected results
fmt.Println("Expected result: map[string]string, cMap")
cMap := make(map[string]string)
for k, v := range(aMap){
cMap[k] = v
}
for k, v := range(cMap){
fmt.Printf("cMap[%s] = %s / %s, aMap[%s] = %s\n",
k, cMap[k], v, k, aMap[k])
}
}
Output
1st method, map[string]*string, bMap
bMap[baz] = foo / foo, aMap[baz] = foo
bMap[foo] = foo / foo, aMap[foo] = bar
bMap[bar] = foo / foo, aMap[bar] = baz
2nd method, map[string]*string, bMap
bMap[baz] = foo / foo, aMap[baz] = foo
bMap[foo] = bar / bar, aMap[foo] = bar
bMap[bar] = baz / baz, aMap[bar] = baz
Expected result: map[string]string, cMap
cMap[baz] = foo / foo, aMap[baz] = foo
cMap[foo] = bar / bar, aMap[foo] = bar
cMap[bar] = baz / baz, aMap[bar] = baz
Thank you so much.
The problem in method 1 is that you aren't taking the address of the string, you're taking the address of the variable it's in. In Go, &v returns the address of variable v. When you have a loop like this:
for k, v := range aMap {
...
}
The variables k and v that you declare at the start of the loop are the same variables used throughout the loop. They are just assigned different values on each iteration. Within that loop &v always evaluates to the same value: the address of v. That's why all of your map entries come out to "foo": "foo" is the last value placed in v, and it's still there.
You can see this behavior in action by changing the string value. All of the map keys will change:
*bMap["foo"] = "quux"
fmt.Println(*bMap["bar"]) // prints "quux"
Method 2 works because every call of a function has its own local variables. Go guarantees that if you return the address of a local variable from a function, that variable will be allocated on the heap where it can be used as long as it's needed. So your helper function is telling Go to allocate a new string variable, copy the passed-in string to it, then return its address.
Here's another method that will work:
dMap := make(map[string]*string)
for k, v := range(aMap){
dMap[k] = new(string)
*dMap[k] = v
}
This allocates a new string variable, saves its address in the map, then copies v into it. If you're going to do this often, the helper function is probably best.
The code you tried like this:
v := "foo"
val := *v
bMap[key] = &val
doesn't work because you're saying, "v is a string; now store the value that string points to in val", but the string isn't a pointer.
The first method in the question uses the address of of the single loop variable v for all keys. The value that you see is the last value set to v.
Fix by declaring a new variable for each iteration and taking the address of that variable.
bMap := make(map[string]*string)
for k, v := range aMap {
v := v // declare new variable v initialized with value from outer v
bMap[k] = &v
}
The second method in the question also declares a new variable for each iteration in the loop. The new variable is the function argument.
This answer shows the idiomatic approach for addressing the issue. See Go FAQ: What happens with closures running as goroutines? for a discussion of the same issue in the context of closures and goroutines.

How to declare variable types for loop variables in Go?

See this code.
package main
import (
"fmt"
)
func main() {
var arr [4]string = [4]string{"foo", "bar", "baz", "qux"}
for a, b := range arr {
fmt.Println(a, b)
}
// How can I fix this code?
/*
for x int, y string = range arr {
fmt.Println(a, b)
}
*/
}
The first for loop uses the := operator to automatically deduce the types of a and b. But what if I want to explicitly specify the types of the loop variables? My attempt to do this is in the second block of commented code which of course failed with the following error.
# command-line-arguments
./foo.go:15: syntax error: unexpected name, expecting {
./foo.go:18: syntax error: unexpected }
Can you help me fix the second block of code such that I can specify the types of x and y explicitly?
Unfortunately the language specification doesn't allow you to declare the variable type in the for loop. The closest you could get is this:
var a int
var b string
for a, b = range arr {
fmt.Println(a, b)
}
But normally if you give your variable meaningful names, their type would be clear as well:
for index, element := range arr {
fmt.Println(index, element)
}
You need to declare first the vars.
var x int
var y string ...// now it should be ok.
for x,y = range arr {
fmt.Println(x, y) // it should be x and y instead of a,b
}
Check the fiddle
First of all your code is not a valid Go code. The for range loop returns the index and the value of an array, slice, string, or map, so there is no reason the explicitly specify the type of the value and the index.
You are specifying the type of the values at the variable initialization, and the language will deduce the type on the range iteration.
One special case is when you are using interface{} as variable type. In this case, you if you need to know the type of the value you can use the reflect package to deduce the type of the value.
switch reflect.TypeOf(t).Kind() {
case reflect.Slice:
s := reflect.ValueOf(t)
for i := 0; i < s.Len(); i++ {
fmt.Println(s.Index(i))
}
}
It's not possible as you are trying to declare two different types of data in same line, if you want explicitly declare variables, then you need to declare them before itself like above answers, but if you want them to be of other type then you need to covert them as for your needs,
package main
import (
"fmt"
)
func main() {
var arr = [4]string{"foo", "bar", "baz", "qux"}
var x int64
var b []byte
for x = 0; x < int64(len(arr)); x++ {
b = []byte(arr[x])
fmt.Println(x, b)
}
}

Difference between := and = operators in Go

What is the difference between the = and := operators, and what are the use cases for them? They both seem to be for an assignment?
In Go, := is for declaration + assignment, whereas = is for assignment only.
For example, var foo int = 10 is the same as foo := 10.
As others have explained already, := is for both declaration, assignment, and also for redeclaration; and it guesses (infers) the variable's type automatically.
For example, foo := 32 is a short-hand form of:
var foo int
foo = 32
// OR:
var foo int = 32
// OR:
var foo = 32
/ There are some rules: /
★ 1st Rule:
You can't use := outside of funcs. It's because, outside a func, a statement should start with a keyword.
// no keywords below, illegal.
illegal := 42
// `var` keyword makes this statement legal.
var legal = 42
func foo() {
alsoLegal := 42
// reason: it's in a func scope.
}
★ 2nd Rule:
You can't use them twice (in the same scope):
legal := 42
legal := 42 // <-- error
Because, := introduces "a new variable", hence using it twice does not redeclare a second variable, so it's illegal.
★ 3rd Rule:
You can use them for multi-variable declarations and assignments:
foo, bar := 42, 314
jazz, bazz := 22, 7
★ 4th Rule (Redeclaration):
You can use them twice in "multi-variable" declarations, if one of the variables is new:
foo, bar := someFunc()
foo, jazz := someFunc() // <-- jazz is new
baz, foo := someFunc() // <-- baz is new
This is legal, because, you're not declaring all the variables, you're just reassigning new values to the existing variables, and declaring new variables at the same time. This is called redeclaration.
★ 5th Rule:
You can use the short declaration to declare a variable in a newer scope even if that variable is already declared with the same name before:
var foo int = 34
func some() {
// because foo here is scoped to some func
foo := 42 // <-- legal
foo = 314 // <-- legal
}
Here, foo := 42 is legal, because, it declares foo in some() func's scope. foo = 314 is legal, because, it just assigns a new value to foo.
★ 6th Rule:
You can declare the same name in short statement blocks like: if, for, switch:
foo := 42
if foo := someFunc(); foo == 314 {
// foo is scoped to 314 here
// ...
}
// foo is still 42 here
Because, foo in if foo := ..., only belongs to that if clause and it's in a different scope.
So, as a general rule: If you want to easily declare a variable you can use :=, or, if you only want to overwrite an existing variable, you can use =.
References:
Short Variable Declaration Rules
A Visual Guide to Go Variables
Only = is the assignment operator.
:= is a part of the syntax of the short variable declaration clause.
👉 There are some rules though. See this other answer for more details.
:= is a short-hand for declaration.
a := 10
b := "gopher"
a will be declared as an int and initialized with value 10 where as b will be declared as a string and initialized with value gopher.
Their equivalents using = would be
var a = 10
var b = "gopher"
= is assignment operator. It is used the same way you would use it in any other language.
You can omit the type when you declare the variable and an initializer is present (http://tour.golang.org/#11).
The := means declare and assign while the = means to simply assign.
:= declares and assigns, = just assigns
It's useful when you don't want to fill up your code with type or struct declarations.
// Usage with =
var i int
var U, V, W float64
var k = 0
var x, y float32 = -1, -2
// Usage with :=
i, j := 0, 10
f := func() int { return 7 }
ch := make(chan int)
from the reference doc : (tour.golang.org)
Inside a function, the := short assignment statement can be used in place of a var declaration with implicit type.
Outside a function, every construct begins with a keyword (var, func, and so on) and the := construct is not available.
In Go
:= is for declaration and assignment also
whereas = is only for the Assignment
for example:
var s string = "Omkar"
s:= "Omkar"

Resources