This snippet works as expected play.golang.org/p/VuCl-OKMav
i := 10
next := 11
prev, i := i, next
However this nearly identical snippet gives non-name f.Bar on left side of := play.golang.org/p/J8NNWPugQG
type Foo struct {
Bar int
}
f := Foo{10}
next := 11
prev, f.Bar := f.Bar, next
What's special about the struct that stops type inference? Is this a bug?
It's an open issue.
Issue 6842: spec: Assigning to fields with short declaration notation
It's not really a type inference issue, it's just that the left-hand-side of := must be a list of identifiers, and f.Bar is not an identifier, so it can't be declared — not even with :='s slightly-more-permissive rules for what it can declare. See "Short variable declarations" in The Go Programming Language Specification.
From the spec's Short variable declarations section:
Unlike regular variable declarations, a short variable declaration may
redeclare variables provided they were originally declared earlier in
the same block...with the same type, and at least one of the non-blank
variables is new.
So if you declare the variable inside another type (struct Foo in the example), it is disqualified by "provided they were originally declared earlier in the same block".
So the answer is to just set the pre-declared variable equal not using the := syntax to the value:
...
var prev int
prev, f.Bar = f.Bar, next
...
it is just that you already assigned f to Foo
f := Foo{100}
in this case f.Bar is 100
so to reassign it just remove the column
var prev string
f := Foo{10}
next := 11
prev, f.Bar = f.Bar, next
this will work
Related
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)
}
In calling a library function with the following signature:
func New() (*sql.DB, Sqlmock, error)
like this:
suite.db, suite.mock, err := sqlmock.New() // inside a suite method
I get error
expected identifier on left side of :=
However, when I change to this
var err error
suite.db, suite.mock, err = sqlmock.New()
the error disappears! Why does declaring k < n variables in a := assignment fail?!
:= is not assignment, it is a short variable declaration. Assignment uses e.g. the simple = operator.
As its name says: it is to declare variables. suite.db is not a variable, it is an expression, more specifically a primary expression; a selector to be exact.
The short variable declaration uses the syntax:
ShortVarDecl = IdentifierList ":=" ExpressionList .
Where IdentifierList is:
IdentifierList = identifier { "," identifier } .
So you must list identifiers. One "exception" to this "declare new variables rule" is the redeclaration:
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.
So you are allowed to use existing variables in a short variable declaration if they were declared in the same block, and you also provide new identifiers (not just existing ones–in which case you would have to use assignment instead).
See related: Why there are two ways of declaring variables in Go, what's the difference and which to use?
When you declare err prior and change := to = it works, because the assignment does not require identifiers on the left of the assignment operator, but expressions:
Assignment = ExpressionList assign_op ExpressionList .
And as detailed above, suite.db is an expression, just like existing variables (identifiers).
:= declares a new variable "identifier". This means you are adding a named thing in your program that can be assigned a value. A struct's fields already are named, as in the golang parser knows they exist so using := makes no sense to golang in this case.
Why does declaring k < n variables in a := assignment fail?!
I'm not sure what "k < n" means, but I think you mean "why does having multiple variables on the left side of := fail?". If that's what you mean, that's not true.
x, y, z := func() (int,int,int) {return 1,2,3}()
fmt.Println(x, y, z)
works just fine. The issue is that golang cannot create an "identifier" (aka a newly named variable) for a struct field since that struct field already exists.
EDIT:
I just had a brainwave that you might have mean "why does having only some new identifiers to declare on the left side of := not work?". This also is not true.
x, y := 5, 6
fmt.Println(x, y)
x, y, z := 1, 2, 3
fmt.Println(x, y, z)
The above works just fine as well.
This snippet works as expected play.golang.org/p/VuCl-OKMav
i := 10
next := 11
prev, i := i, next
However this nearly identical snippet gives non-name f.Bar on left side of := play.golang.org/p/J8NNWPugQG
type Foo struct {
Bar int
}
f := Foo{10}
next := 11
prev, f.Bar := f.Bar, next
What's special about the struct that stops type inference? Is this a bug?
It's an open issue.
Issue 6842: spec: Assigning to fields with short declaration notation
It's not really a type inference issue, it's just that the left-hand-side of := must be a list of identifiers, and f.Bar is not an identifier, so it can't be declared — not even with :='s slightly-more-permissive rules for what it can declare. See "Short variable declarations" in The Go Programming Language Specification.
From the spec's Short variable declarations section:
Unlike regular variable declarations, a short variable declaration may
redeclare variables provided they were originally declared earlier in
the same block...with the same type, and at least one of the non-blank
variables is new.
So if you declare the variable inside another type (struct Foo in the example), it is disqualified by "provided they were originally declared earlier in the same block".
So the answer is to just set the pre-declared variable equal not using the := syntax to the value:
...
var prev int
prev, f.Bar = f.Bar, next
...
it is just that you already assigned f to Foo
f := Foo{100}
in this case f.Bar is 100
so to reassign it just remove the column
var prev string
f := Foo{10}
next := 11
prev, f.Bar = f.Bar, next
this will work
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"
I'm following this tutorial, specifically exercise 8:
http://tour.golang.org/#8
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("hello", "world")
fmt.Println(a, b)
}
Specifically what does the := mean? Searching for Go documentation is very hard, ironically.
A short variable declaration uses the syntax:
ShortVarDecl = IdentifierList ":=" ExpressionList .
It is a shorthand for a regular variable declaration with initializer expressions but no types:
Keep on going to page 12 of the tour!
A Tour of Go
Short variable declarations
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 and the :=
construct is not available.)
As others have explained already, := is for both declaration, and assignment, whereas = is for assignment only.
For example, var abc int = 20 is the same as abc := 20.
It's useful when you don't want to fill up your code with type or struct declarations.
The := syntax is shorthand for declaring and initializing a variable, example f := "car" is the short form of var f string = "car"
The short variable declaration operator(:=) can only be used for declaring local variables. If you try to declare a global variable using the short declaration operator, you will get an error.
Refer official documentation for more details
:= is not an operator. It is a part of the syntax of the Short variable declarations clause.
more on this: https://golang.org/ref/spec#Short_variable_declarations
According to my book on Go, it is just a short variable declaration statement
exactly the same as
var s = ""
But it is more easy to declare, and the scope of it is less expansive. A := var decleration also can't have a type of interface{}. This is something that you will probably run into years later though
:= represents a variable, we can assign a value to a variable using :=.