Is it possible to include values in the declaration of a new type.
type Vertex struct {
X, Y int
}
func main() {
v := new( Vertex{ 0, 0} ) // Like so
fmt.Println( v )
// Instead of :
v = new(Vertex)
v.X, v.Y = 12, 4 // extra line for initializing the values of X and Y
fmt.Println( v )
}
Or because go makes the "Vertex{val, val} " a literal value instead of a basic Vertex type it's not possible?
You don't actually need "new", you can simply write:
v := Vertex{1,2}
If you want a struct with all members set to the zero value of their types (e.g., 0
for ints, nil for pointers, "" for strings, etc.), it's even simpler:
v := Vertex{} // same as Vertex{0,0}
You can also only initialize some of the members, leaving the others with their zero value:
v := Vertex{Y:1} // same as Vertex{0,1}
Note that with these v will be a variable of type Vertex. If you want a pointer to a Vertex, use:
v := &Vertex{1,2}
Related
If I use container/list as
package main
import (
"container/list"
"fmt"
)
type Data struct {
x int
}
func main() {
l := list.New()
l.PushBack(Data{2})
a := l.Back()
v := a.Value.(Data)
v.x = 1
fmt.Println(l.Back().Value) // --> {2}
}
Well, the value of x in the list does not change. What is the correct programming pattern?
Function arguments and return values are passed by value in Go. Therefore v is a copy of the original Data value. Changing it does not affect the one that is stored in the list.
You can get the behaviour you want by inserting a pointer to a Data value instead:
l := list.New()
l.PushBack(&Data{2})
a := l.Back()
v := a.Value.(*Data)
v.x = 1
fmt.Println(l.Back().Value) // --> &{1}
I have created a generic data structure, with a name and a generic array in Golang.
package main
import "fmt"
type NamedArray struct {
Name string
values []interface{}
}
func main() {
data := [...]int{1, 2, 3, 4, 5}
interfaced_data := make([]interface{}, len(data))
for i, v := range data{
interfaced_data[i] = v
}
int_arr := NamedArray{Name: "Int Array", values: interfaced_data}
fmt.Println(int_arr)
// fmt.Println(int_arr.Sum()) -- uncomment to run Sum
data_float := [...]float64{0.1, 0.2, 0.3, 0.4, 0.5}
interfaced_data_float := make([]interface{}, len(data_float))
for i, v := range data_float{
interfaced_data_float[i] = v
}
float_arr := NamedArray{Name: "Float Array", values: interfaced_data_float}
fmt.Println(float_arr)
// fmt.Println(int_arr.Sum()) -- uncomment to run Sum
}
Now I want to define a method which allows me to sum all the values in the array. I know that they are numeric (though whether they are int or float is dependant on context) but I am having some serious trouble.
func (arr NamedArray) Sum() interface{} {
data := arr.values
sum := 0
for i, v := range data {
sum += v
}
return sum
}
I can't seem to make this work, though. When I uncomment lines 18 and 27 (fmt.Println(int_arr.Sum() and fmt.Println(int_arr.Sum()) and try to run the code I get
34:9: invalid operation: sum += v (mismatched types int and interface {})
During compilation.
Does anyone know how to add generic types, given we know that they are numeric?
Thanks!
The + operator is not defined on values of type interface{}. You have to get a value of type int out of the interface{} values before you can work with it as a number.
For that, you may use type assertion. See this example:
s := []interface{}{1, 2, 3, "invalid"}
sum := 0
for _, v := range s {
if i, ok := v.(int); ok {
sum += i
} else {
fmt.Println("Not int:", v)
}
}
fmt.Println("Sum:", sum)
Output (try it on the Go Playground):
Not int: invalid
Sum: 6
The above example only handles int numbers, and nothing else. If you want to "support" multiple number types, a more convenient way would be to use a type switch:
s := []interface{}{1, int32(2), int8(3), "invalid"}
sum := 0
for _, v := range s {
switch i := v.(type) {
case int:
sum += i
case int32:
sum += int(i)
case int8:
sum += int(i)
default:
fmt.Println("Not int:", v)
}
}
fmt.Println("Sum:", sum)
Output is the same. Try this one on the Go Playground.
This question already has an answer here:
golang pointer in range doesn't work
(1 answer)
Closed 4 years ago.
For these two struct
type A struct {
Number *int
}
type B struct {
Number int
}
If I want to loop on slice of B and assign the value of B.Number to new A.Number
func main() {
aSlice := []A{}
bSlice := []B{B{1}, B{2}, B{3}}
for _, v := range bSlice {
a := A{}
a.Number = &v.Number
aSlice = append(aSlice, a)
}
}
I will found that all aSlice a.Number is the same value and same pointer.
for _, v := range aSlice {
fmt.Printf("aSlice Value %v Pointer %v\n", *v.Number,v.Number)
}
Will print
aSlice Value 3 Pointer 0x10414020
aSlice Value 3 Pointer 0x10414020
aSlice Value 3 Pointer 0x10414020
So does range only update the value of _,v in for loop and doesn't change the pointer ?
Full Code : https://play.golang.org/p/2wopH9HOjwj
It occurred because variable v is created at the beginning of the loop and doesn't change. So, every element in aSlice has a pointer to the same variable. You should write this:
for _, v := range bSlice {
a := A{}
v := v
a.Number = &v.Number
aSlice = append(aSlice, a)
}
Here you create at every iteration new variable with its own pointer.
As #Adrian stated This has nothing to do with memory. The A struct is actually contains a pointer to integer value.
type A struct {
Number *int
}
So when you are assigning the value from bSlice to A struct and then appending the A struct in aSlice which is of A struct type. It will append the values as it is supposed to do inside Golang.
But you are changing the value at address pointed by A struct. And initialed with a new value in each iteration which changes the value at that address.
a.Number = &v.Number // here a.Number points to the same address
Hence the aSlice contains the value of last updated integer which is 3. Since aSlice is a slice of A struct it contains the value inside A struct which is 3.
But if you do not create a pointer to int inside A struct
type A struct {
Number int
}
you will get the output as expected with different address now as.
package main
import (
"fmt"
)
type A struct {
Number int
}
type B struct {
Number int
}
func main() {
aSlice := []A{}
bSlice := []B{B{1}, B{2}, B{3}}
fmt.Println("----Assignment Loop----")
for _, v := range bSlice {
a := A{}
a.Number = v.Number
aSlice = append(aSlice, a)
fmt.Printf("bSlice Value %v Pointer %v\n", v.Number, &v.Number)
fmt.Printf(" a Value %v Pointer %v\n", a.Number, &a.Number)
}
fmt.Println("\n----After Assignment----")
fmt.Printf("%+v\n", aSlice)
for i, _ := range aSlice {
fmt.Println(aSlice[i].Number)
}
}
Working Code on Go playground
In Golang spec It is defined for composite Literals as :
Taking the address of a composite literal generates a pointer to a
unique variable initialized with the literal's value.
type Point3D struct { x, y, z float64 }
var pointer *Point3D = &Point3D{y: 1000}
I am taking the "Tour of Go", and had a question regarding the Exercise: Slices example. Currently I can create the picture by iterating over each index using the the [] operator, just like you could in C.
func Pic(dx, dy int) [][]uint8 {
pic := make([][]uint8, dy)
for i := range pic {
pic[i] = make([]uint8, dx)
for j := range pic[i] {
pic[i][j] = uint8(1)
}
}
return pic
}
However, when I try to do something like below, I get an panic: runtime error: index out of range error. I tried adding print statements and calling Pic(3, 3), which printed out a 3x3 array just fine.
func Pic(dx, dy int) [][]uint8 {
pic := make([][]uint8, dy)
for _, y := range pic {
y = make([]uint8, dx)
for _, x := range y {
x = uint8(1)
_ = x // x has to be used
//fmt.Print("1")
}
//fmt.Print("\n")
}
return pic
}
Any thoughts on what I am doing wrong?
The main problem is your attempt to do assignment. Check my example using your code; https://play.golang.org/p/lwoe79jQ70
What you actually get out of the latter implementation is a 3x0 array, all of the inner arrays are empty. The reason for this is because you're using the range variable for assignment which doesn't work. If the current index is 0, y != pic[0], pic[0] is assigned to y however, y is temporary storage, it typically is the same address and is over written on each iteration. So after the latter example executes, all your x direction arrays are empty, indexing into one causes a panic.
Basically you should just be using your first implementation because it works fine and is the way you would typically do this. But the take away is, when you do a, b := range Something b != Something[a], it is it's on instance, it goes out of scope at the bottom of the loop and assigning to it will not cause a state change to the collection Something, instead you must assign to Something[a] if you want to modify Something[a].
range copies the values from the slice you're iterating over.
See: http://golang.org/ref/spec#RangeClause
To clarify what happens see this simple code example and its output:
package main
import "fmt"
func main() {
s := "hi"
//s[0] = 'H' // cannot assign to s[0]
for _, v := range s {
fmt.Printf("%T, %[1]v, %X\n", v, &v)
v = 'H' // has no effect: this is local var not ref
}
fmt.Println(s)
}
The output is:
int32, 104, C0820042D4
int32, 105, C0820042D4
hi
As you see the address of variable v is not changing (C0820042D4) and v is local variable and range copies value to it, so changing v has no effect.
Here v is rune (int32 alias), A rune is an integer value identifying a Unicode code point, and you cannot assign to s[0] and this won’t compile: s[0] = 'H'
so v = 'H' has no effect on s, it is just local variable.
Is it possible to declare multiple variables at once using Golang?
For example in Python you can type this:
a = b = c = 80
and all values will be 80.
Yes, you can:
var a, b, c string
a = "foo"
fmt.Println(a)
You can do something sort of similar for inline assignment, but not quite as convenient:
a, b, c := 80, 80, 80
Another way to do this is like this
var (
a = 12
b = 3
enableFeatureA = false
foo = "bar"
myvar float64
anothervar float64 = 2.4
)
Also works for const
const (
xconst = 5
boolconst = false
)
In terms of language specification, this is because the variables are defined with:
VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) .
VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
(From "Variable declaration")
A list of identifiers for one type, assigned to one expression or ExpressionList.
const a, b, c = 3, 4, "foo" // a = 3, b = 4, c = "foo", untyped integer and string constants
const u, v float32 = 0, 3 // u = 0.0, v = 3.0
Yes you can and it is slightly more nuanced than it seems.
To start with, you can do something as plain as:
var a, b, x, y int // declares four variables all of type int
You can use the same syntax in function parameter declarations:
func foo(a, b string) { // takes two string parameters a and b
...
}
Then comes the short-hand syntax for declaring and assigning a variable at the same time.
x, y := "Hello", 10 // x is an instance of `string`, y is of type `int`
An oft-encountered pattern in Golang is:
result, err := some_api(...) // declares and sets `result` and `err`
if err != nil {
// ...
return err
}
result1, err := some_other_api(...) // declares and sets `result1`, reassigns `err`
if err != nil {
return err
}
So you can assign to already-defined variables on the left side of the := operator, so long as at least one of the variables being assigned to is new. Otherwise it's not well-formed. This is nifty because it allows us to reuse the same error variable for multiple API calls, instead of having to define a new one for each API call. But guard against inadvertent use of the following:
result, err := some_api(...) // declares and sets `result` and `err`
if err != nil {
// ...
return err
}
if result1, err := some_other_api(...); err != nil { // result1, err are both created afresh,
// visible only in the scope of this block.
// this err shadows err from outer block
return err
}
Several answers are incorrect: they ignore the fact that the OP is asking whether it is possible to set several variables to the same value in one go (sorry for the pun).
In go, it seems you cannot if a, b, c are variables, ie you will have to set each variable individually:
a, b, c := 80, 80, 80
But if a, b, c are constants, you can:
const (
a = 80
b
c
)
Try this in the go-playground:
https://play.golang.org/
package main
import "fmt"
func main() {
a, b := "a", "b"; //Declare And Assign
var c, d string; //Declare Only
fmt.Println(a,b);
fmt.Println(c,d);
}
Another way of doing is using var for package level assignment
package main
import (
"fmt"
)
var (
a, b, c = 80, 80 ,80
)
func main() {
fmt.Println(a, b, c)
}
long declaration
var varName1, varName2 string = "value","value"
short declaration
varName1,varName2 := "value1","value2"