How to declare variable types for loop variables in Go? - for-loop

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)
}
}

Related

Pointing map to a new map inside a method looses effect after leaving method

This code, visible on the Go PlayGround:
package main
import "fmt"
type MyType map[int]int
func (x MyType) updateIt() {
newItem := make(MyType)
for i := 0; i < 3; i++ {
newItem[i] = i
}
x = newItem
fmt.Println(x)
}
func main() {
x := make(MyType)
x.updateIt()
fmt.Println(x)
}
Produces:
map[0:0 1:1 2:2]
map[]
While I expect:
map[0:0 1:1 2:2]
map[0:0 1:1 2:2]
Why?
My understanding is that: x.updateIt() takes x as an argument, then creates newItem and changes the pointer of x so that it points to newItem. So x points to the data of newItem. This seems to be indeed the case inside updateIt, as visible from the first print line. But when x is print after the method, the change is lost.
I'm new to Go and this is unexpected behaviour for me, could you please explain?
You should be using a pointer receiver:
func (x *MyType) updateIt() {
newItem := make(MyType)
for i := 0; i < 3; i++ {
newItem[i] = i
}
*x = newItem
fmt.Println(x)
}
Playground: https://play.golang.org/p/K82TTjHdDgg
Explanation
Arguments "in front" of a function (so-called receivers) behave more or less like ordinary arguments.
Imagine a function like this:
func updateIt(x MyType) {
newItem := make(MyType)
for i := 0; i < 3; i++ {
newItem[i] = i
}
x = newItem
fmt.Println(x)
}
Here, you pass x by value, not by reference (or as a pointer).
What happens is that x gets replaced inside the function, but keeps its original value outside of it. By passing a pointer you can replace the value to which x is pointing, thereby changing the value of x outside of the function.
See also "A Tour of Go, Pointers": https://tour.golang.org/moretypes/1
Inside the main function you create a new map and assign the pointer of that new map to x.
Then the value of that pointer is passed to the updateIt function.
Then inside updateIt you replace it with pointer to another map you create inside updateIt. Then it updates this new map instead of updating the original map created inside main
The most important thing to understand here is that your program creates two different maps.
So avoid creating two maps and update the same map passed to your updateIt function.
func (x MyType) updateIt() {
for i := 0; i < 3; i++ {
x[i] = i
}
fmt.Println(x)
}
https://play.golang.org/p/-MemfTv1uJV

Why golang slice is empty after initialization?

My question here is why the slice is empty in another func when the slice is global to the file?
Here's a piece of code:
package main
import "fmt"
type Vec3 struct {
x float32
y float32
z float32
}
var a []Vec3
func main() {
a := make([]Vec3, 0)
a = append(a, Vec3{2.0, 3.0, 4.0})
a = append(a, Vec3{3.4, 5.6, 5.4})
a = append(a, Vec3{6.7, 4.5, 7.8})
fmt.Printf("%+v\n", a)
doSomethingWithA();
}
func doSomethingWithA() {
fmt.Printf("%+v\n", a)
}
Output:
[{x:2 y:3 z:4} {x:3.4 y:5.6 z:5.4} {x:6.7 y:4.5 z:7.8}]
[]
This is a repl.it link too, if you want to take a look.
Thanks for your kind help.
You have redefined it here:
a := make([]Vec3, 0)
To use the same variable you should assign a value with = but not declare a new variable with :=
a = make([]Vec3, 0)
Short variable declarations
Inside a function, the := short assignment statement can be used in place of a var declaration with implicit type.
You are re declaring a, so actually you not initializing the global var, try:
a = make([]Vec3, 0)

What is the difference between := and = in 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

Modify array of interface{} golang

This type assertion, def-referencing has been driving me crazy. So I have a nested structure of Key string / Value interface{} pairs. Stored in the Value is an []interface which I want to modify each of the values. Below is an example of creating an array of Bar and passing it into the ModifyAndPrint function which should modify the top level structure. The problem that I come accross is as written it doesn't actually modify the contents of z, and I can't do a q := z.([]interface{})[i].(Bar) or & thereof.
Is there a way to do this? If so, what combination did I miss?
package main
import "fmt"
type Bar struct {
Name string
Value int
}
func ModifyAndPrint(z interface{}){
fmt.Printf("z before: %v\n", z)
for i, _ := range(z.([]interface{})) {
q := z.([]interface{})[i]
b := (q).(Bar)
b.Value = 42
fmt.Printf("Changed to: %v\n", b)
}
fmt.Printf("z after: %v\n", z)
}
func main() {
bars := make([]interface{}, 2)
bars[0] = Bar{"a",1}
bars[1] = Bar{"b",2}
ModifyAndPrint(bars)
}
https://play.golang.org/p/vh4QXS51tq
The program is modifying a copy of the value in the interface{}. One way to achieve your goal is to assign the modified value back to the slice:
for i, _ := range(z.([]interface{})) {
q := z.([]interface{})[i]
b := (q).(Bar)
b.Value = 42
z.([]interface{})[i] = b
fmt.Printf("Changed to: %v\n", b)
}
playground example

Shortest way / Shorthand to declare variable in go

We can use the following syntax for go variable declaration
var num int
var str string
but is there any shorthand in go for doing the same thing?
for example we can do so in python simply saying:
num = 13
strings = "Hello World"
or even
num, strings = 13,"Hello World"
The variable declaration can initialize multiple variables:
var x, y float32 = -1, -2
Or (short variable declaration with :=)
i, j := 0, 10
So this would work: play.golang.org
package main
import "fmt"
func main() {
a, b := 1, "e"
fmt.Printf("Hello, playground %v %v", b, a)
}
Output:
Hello, playground e 1
The := syntax is shorthand for declaring and initializing a Go variable .
For example:
to declare e string var we can simple use
str := "Hello world"
Short variable declarations
The := operator is the short variable declaration operator. This operator is used to both declare and initialize a variable.
Example:
package main
import "fmt"
func main() {
firstName := "Joey"
fmt.Println(firstName)
}
The variable type is not vital because the Go compiler is able to derive the type based on the value you have assigned. Since we are assigning a string to firstName, firstName is allocated as a variable type as string.

Resources