Understanding go nested structs - data-structures

I'm trying to understand nested structs in go, so I made a little test: (playground)
type A struct {
a string
}
type B struct {
A
b string
}
func main() {
b := B{A{"a val"}, "b val"}
fmt.Printf("%T -> %v\n", b, b) // B has a nested A and some values
// main.B -> {{a val} b val}
fmt.Println("b.b ->", b.b) // B's own value
// b.b -> b val
fmt.Println("b.A.a ->", b.A.a) // B's nested value
// b.a -> a val
fmt.Println("b.a ->", b.a) // B's nested value? or own value?
// b.a -> a val
}
So how and why the last two lines work? Are they are same? Which should I use?

They are the same. See the Go Spec on selectors:
For a value x of type T or *T where T is not a pointer or interface type, x.f denotes the field or method at the shallowest depth in T where there is such an f. If there is not exactly one f with shallowest depth, the selector expression is illegal.
Note that this means that b.a is illegal if type B embeds two types with the same field on the same depth:
type A1 struct{ a string }
type A2 struct{ a string }
type B struct {
A1
A2
}
// ...
b := B{A1{"a1"}, A2{"a2"}}
fmt.Println(b.a) // Error: ambiguous selector b.a
Playground: http://play.golang.org/p/PTqm-HzBDr.

Related

What is the evaluation order of function arguments?

I'm using this version of Go:
$ go version
go version go1.18 windows/amd64
The results are different when struct A has only one field and B has two or above fields, and it just happens when parameter type is interface.
I'm not sure if that's a bug:
package main
import (
"fmt"
)
func main() {
a := A{}
m("A", a, SetAI(&a))
b := B{}
m("B", b, SetBI(&b))
}
type A struct {
I int
S string
}
type B struct {
I int
}
func SetAI(a *A) A {
a.I = 10
return *a
}
func SetBI(b *B) B {
b.I = 10
return *b
}
func m(name string, arg1, arg2 interface{}) {
fmt.Println(name+":", arg1, arg2)
}
I expected this output:
A: {10} {10}
B: {10} {10}
Instead I got this:
A: {0 } {10 }
B: {10} {10}
The source of confusion and different output is the order of evaluation of the arguments.
Look at your example:
m("A", a, SetAI(&a))
This is a function call, the function value and arguments are evaluated in the usual order:
Otherwise, when evaluating the operands of an expression, assignment, or return statement, all function calls, method calls, and communication operations are evaluated in lexical left-to-right order.
For example, in the (function-local) assignment
y[f()], ok = g(h(), i()+x[j()], <-c), k()
the function calls and communication happen in the order f(), h(), i(), j(), <-c, g(), and k(). However, the order of those events compared to the evaluation and indexing of x and the evaluation of y is not specified.
So basically the spec only guarantees that function calls and communication
ops happen from left-to-right.
Your call has arguments "A", a and SetAI(&a). There is no guarantee if the second argument a is evaluated before the &a param passed to SetAI(), and this very much matters because SetAI() modifies a. Since the order is not guaranteed, you can't rely on which will be evaluated first, both order is valid by the spec.
If you make the evaluation explicit by doing a copy of the struct before, you get the same result:
a := A{}
aCopy := a
m("A", aCopy, SetAI(&a))
b := B{}
bCopy := b
m("B", bCopy, SetBI(&b))
This will output (try it on the Go Playground):
A: {0 } {10 }
B: {0} {10}
Or if you want the function call to be evaluated first:
a := A{}
ap := SetAI(&a)
m("A", a, ap)
b := B{}
bp := SetBI(&b)
m("B", b, bp)
This will output 10 for each cases (try this one on the Go Playground):
A: {10 } {10 }
B: {10} {10}

Type definition - cannot use basic type as custom type even though basic type is source of custom type

In the below code, we are using type definition syntax in Line 5,6,7:
package math
// Constructors and Selectors
type RationalNumber []int // Line 5
type Numerator int
type Denominator int
// Constructor - Construct a rational number x that represents n/d
func NewRationalNumber(n int, d int) RationalNumber {
g := gcd(n, d)
return []int{n / g, d / g} // Line 12
}
//Selector
func numer(x RationalNumber) Numerator {
return x[0] // Line 17
}
//Selector
func denom(x RationalNumber) Denominator {
return x[1]
}
return []int{n / g, d / g} does not give error,
where as,
return x[0] & return x[1] give error:
math/numbers.go:17:10: cannot use x[0] (type int) as type Numerator in return argument
math/numbers.go:22:10: cannot use x[1] (type int) as type Denominator in return argument
For given 3 type definitions in Line 5,6,7, I understand the reason behind error on Line 17, but,
Why Line 12 does not give similar error?
How to resolve this error? without changing the signature of functions?
The defined type RationalNumber was created from a slice with elements of type int, therefore subscription on an instance of the defined type gives an int, not any of the newly defined types created from int.
The compiler does not complain about line 12 since the syntax is the slice literal appropriate for creating the defined type (hint: elements of new slice type are int).
You are returning a type different from what was specified in the function definitions.
Take numer(x RationalNumber) Numerator for example
numer(x RationalNumber) Numerator accepts a variable of type RationalNumber and is expected to return a variable of type Numerator.
The problem is that you are returning a type int (as RationalNumber is a slice of ints) but a type Numerator is expected.
You can refactor your code to cast the int returned by RationalNumber to the appropriate types.
type RationalNumber []int
type Numerator int
type Denominator int
func NewRationalNumber(n int, d int) RationalNumber {
g := gcd(n, d)
return []int{n / g, d / g}
}
func numer(x RationalNumber) Numerator {
return Numerator(x[0])
}
func denom(x RationalNumber) Denominator {
return Denominator(x[1])
}
I know that, my question is why there is no necessity to do RationalNumber([]int{n / g, d / g})?
You do not need to do so because []int{n/g, d/g} is already a slice of ints.
type Numerator = int syntax is resolving the error. Am not sure, how type Numerator = int different from type Numerator int? No need to Numerator(x[0])
type Numerator = int is a type alias for int. This does not create a new type that is distinct from int.
Whereas type Numerator int creates a new custom type called Numerator which has a source type of int. Numerator can be cast to int but it is distinct from int
You can refer to Type definitions vs Type Alias for more explanations
This question bothered me as well, so here is answer that i came up with.
Take your function as an example:
func NewRationalNumber(n int, d int) RationalNumber {
g := gcd(n, d)
return []int{n / g, d / g}
}
According to function signature, it should return RationalNumber type, but in fact it returns int slice. Reason why it works is that type []int is assignable to type RationalNumber. Specifically it satisfies second condition, mentioned in language spec:
x's type V and T have identical underlying types and at least one of V or T is not a defined type.
This condition is satisfied, because in that case, we have only one defined type(RationalNumber) and another one is composite type([]int).
So, why do we get error when we define following function?:
func numer(x RationalNumber) Numerator {
return x[0]
}
Type Numerator has int as underlying type and we return int, which is predeclared type, so it should work, right? No) Thing is, although int is predeclared, it's still defined type. As it's stated in language spec:
To avoid portability issues all numeric types are defined types
In fact, all predeclared types, except error, are defined types.

swap function not working in golang

Actually i just start to learn golang . In the beginning i think that = and := are same . But then i understand that there is some difference between this two .
I learned swap function in golnag
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("hello", "world")
fmt.Println(a, b)
}
But when i rewrite this function using var this is not working
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
var a, b string
a ="hello"
b="world"
swap(a, b)
fmt.Println(a, b)
}
what is the error in this program ?
Another solution is to use pointers:
package main
import "fmt"
func swap(x, y *string) {
*x, *y = *y, *x
}
func main() {
var a, b string
a ="hello"
b="world"
swap(&a, &b)
fmt.Println(a, b)
}
https://play.golang.org/p/-vxUMlaVmN
The reason is that in second case values returned from swap are ignored. SO nothing is changed.
Try: https://play.golang.org/p/uADEf5X15g
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
var a, b string
a = "hello"
b = "world"
a, b = swap(a, b) //// <----
fmt.Println(a, b)
}
To respond your initial question, you should assign the values returned by swap to a and b like so
a, b = swap(b, a)
Notice that this is simple assignment , without the : attached to the equal
also, instead of a swap function, you could just try inplace reassignment:
a, b = b, a
Variables declaration
var a string - declaration of a variable with null value
a := "spam" - declaration of a variable with a concrete value
func f(a, b string) (string, string) { - declaration of a function with value parameters. It means you have new variables with passed values as arguments each time you call a function.
func f(a, b *string) (*string, *string) { - declaration of a function with pointer arguments. In it's turn it means you have pointers to passed variables each time you call the function.
Also...
a := *string - declaration of a pointer variable.
*a - value of a pointer variable.
&a - pointer of a value
In-place swap
To swap in-place (without returning and reassigning) you should swap values between pointers.
func swap(a, b *string) {
*a, *b = *b, *a
}
p.s.
Take into account that strings is read-only slices of bytes. And slices are reference type it means that an array behind the sub-slices of a common array or slice is the same. It doesn't related to the question but should be considered in such cases.

Explain Type Assertions in Go

I'm reading about type assertions x.(T) in The Go Programming Language and don't understand them.
I understand that there are different scenarios:
T is a concrete type or an interface
One (asserted value?) or two (ok) values can be returned
This is what I don't understand:
Why would I use them?
What exactly do they return?
I have also googled on the topic and still don't understand.
Short answer
In one line:
x.(T) asserts that x is not nil and that the value stored in x is of type T.
Why would I use them:
to check x is nil
to check what is the dynamic type held by interface x
to extract the dynamic type from x
What exactly they return:
t := x.(T) => t is of type T; if x is nil, it panics.
t,ok := x.(T) => if x is nil or not of type T => ok is false otherwise ok is true and t is of type T.
Detailed explanation
Imagine you need to calculate area of 4 different shapes: Circle, Square, Rectangle and Triangle. You may define new types with a new method called Area(), like this:
type Circle struct {
Radius float64
}
func (t Circle) Area() float64 {
return math.Pi * t.Radius * t.Radius
}
And for Triangle :
type Triangle struct {
A, B, C float64 // lengths of the sides of a triangle.
}
func (t Triangle) Area() float64 {
p := (t.A + t.B + t.C) / 2.0 // perimeter half
return math.Sqrt(p * (p - t.A) * (p - t.B) * (p - t.C))
}
And for Rectangle :
type Rectangle struct {
A, B float64
}
func (t Rectangle) Area() float64 {
return t.A * t.B
}
And for Square:
type Square struct {
A float64
}
func (t Square) Area() float64 {
return t.A * t.A
}
Here you have Circle, with radius of 1.0, and other shapes with their sides:
shapes := []Shape{
Circle{1.0},
Square{1.772453},
Rectangle{5, 10},
Triangle{10, 4, 7},
}
Interesting! How can we collect them all in one place?
First you need Shape interface to collect them all in one slice of shape []Shape :
type Shape interface {
Area() float64
}
Now you can collect them like this:
shapes := []Shape{
Circle{1.0},
Square{1.772453},
Rectangle{5, 10},
Triangle{10, 4, 7},
}
After all, Circle is a Shape and Triangle is a Shape too.
Now you can print the area of each shape using the single statement v.Area():
for _, v := range shapes {
fmt.Println(v, "\tArea:", v.Area())
}
So Area() is a common interface between all shapes.
Now, how can we calculate and call uncommon method like angles of triangle using above shapes?
func (t Triangle) Angles() []float64 {
return []float64{angle(t.B, t.C, t.A), angle(t.A, t.C, t.B), angle(t.A, t.B, t.C)}
}
func angle(a, b, c float64) float64 {
return math.Acos((a*a+b*b-c*c)/(2*a*b)) * 180.0 / math.Pi
}
Now it's time to extract Triangle from above shapes:
for _, v := range shapes {
fmt.Println(v, "\tArea:", v.Area())
if t, ok := v.(Triangle); ok {
fmt.Println("Angles:", t.Angles())
}
}
Using t, ok := v.(Triangle) we requested type assertions, meaning we asked the compiler to try to convert v of type Shape to type Triangle, so that if it's successful, the ok will be true otherwise false, and then if it is successful call t.Angles() to calculate the triangle's three angles.
This is the output:
Circle (Radius: 1) Area: 3.141592653589793
Square (Sides: 1.772453) Area: 3.1415896372090004
Rectangle (Sides: 5, 10) Area: 50
Triangle (Sides: 10, 4, 7) Area: 10.928746497197197
Angles: [128.68218745348943 18.194872338766785 33.12294020774379]
And the whole working sample code:
package main
import "fmt"
import "math"
func main() {
shapes := []Shape{
Circle{1.0},
Square{1.772453},
Rectangle{5, 10},
Triangle{10, 4, 7},
}
for _, v := range shapes {
fmt.Println(v, "\tArea:", v.Area())
if t, ok := v.(Triangle); ok {
fmt.Println("Angles:", t.Angles())
}
}
}
type Shape interface {
Area() float64
}
type Circle struct {
Radius float64
}
type Triangle struct {
A, B, C float64 // lengths of the sides of a triangle.
}
type Rectangle struct {
A, B float64
}
type Square struct {
A float64
}
func (t Circle) Area() float64 {
return math.Pi * t.Radius * t.Radius
}
// Heron's Formula for the area of a triangle
func (t Triangle) Area() float64 {
p := (t.A + t.B + t.C) / 2.0 // perimeter half
return math.Sqrt(p * (p - t.A) * (p - t.B) * (p - t.C))
}
func (t Rectangle) Area() float64 {
return t.A * t.B
}
func (t Square) Area() float64 {
return t.A * t.A
}
func (t Circle) String() string {
return fmt.Sprint("Circle (Radius: ", t.Radius, ")")
}
func (t Triangle) String() string {
return fmt.Sprint("Triangle (Sides: ", t.A, ", ", t.B, ", ", t.C, ")")
}
func (t Rectangle) String() string {
return fmt.Sprint("Rectangle (Sides: ", t.A, ", ", t.B, ")")
}
func (t Square) String() string {
return fmt.Sprint("Square (Sides: ", t.A, ")")
}
func (t Triangle) Angles() []float64 {
return []float64{angle(t.B, t.C, t.A), angle(t.A, t.C, t.B), angle(t.A, t.B, t.C)}
}
func angle(a, b, c float64) float64 {
return math.Acos((a*a+b*b-c*c)/(2*a*b)) * 180.0 / math.Pi
}
Also see:
Type assertions
For an expression x of interface type and a type T, the primary
expression
x.(T)
asserts that x is not nil and that the value stored in x is of type T. The notation x.(T) is called a type assertion.
More precisely, if T is not an interface type, x.(T) asserts that the
dynamic type of x is identical to the type T. In this case, T must
implement the (interface) type of x; otherwise the type assertion is
invalid since it is not possible for x to store a value of type T. If
T is an interface type, x.(T) asserts that the dynamic type of x
implements the interface T.
If the type assertion holds, the value of the expression is the value
stored in x and its type is T. If the type assertion is false, a
run-time panic occurs. In other words, even though the dynamic type of
x is known only at run time, the type of x.(T) is known to be T in a
correct program.
var x interface{} = 7 // x has dynamic type int and value 7
i := x.(int) // i has type int and value 7
type I interface { m() }
var y I
s := y.(string) // illegal: string does not implement I (missing method m)
r := y.(io.Reader) // r has type io.Reader and y must implement both I and io.Reader
A type assertion used in an assignment or initialization of the
special form
v, ok = x.(T)
v, ok := x.(T)
var v, ok = x.(T)
yields an additional untyped boolean value. The value of ok is true if
the assertion holds. Otherwise it is false and the value of v is the
zero value for type T. No run-time panic occurs in this case.
EDIT
Question: What does the assertion x.(T) return when T is an interface{} and not a concrete type?
Answer:
It asserts that x is not nil and that the value stored in x is of type T.
E.g. this panics (compile: Success, Run: panic: interface conversion: interface is nil, not interface {}):
package main
func main() {
var i interface{} // nil
var _ = i.(interface{})
}
And this works (Run: OK):
package main
import "fmt"
func main() {
var i interface{} // nil
b, ok := i.(interface{})
fmt.Println(b, ok) // <nil> false
i = 2
c, ok := i.(interface{})
fmt.Println(c, ok) // 2 true
//var j int = c // cannot use c (type interface {}) as type int in assignment: need type assertion
//fmt.Println(j)
}
Output:
<nil> false
2 true
NOTE: here c is of type interface {} and not int.
See this working sample code with commented outputs:
package main
import "fmt"
func main() {
const fm = "'%T'\t'%#[1]v'\t'%[1]v'\t%v\n"
var i interface{}
b, ok := i.(interface{})
fmt.Printf(fm, b, ok) // '<nil>' '<nil>' '<nil>' false
i = 2
b, ok = i.(interface{})
fmt.Printf(fm, b, ok) // 'int' '2' '2' true
i = "Hi"
b, ok = i.(interface{})
fmt.Printf(fm, b, ok) // 'string' '"Hi"' 'Hi' true
i = new(interface{})
b, ok = i.(interface{})
fmt.Printf(fm, b, ok) // '*interface {}' '(*interface {})(0xc042004330)' '0xc042004330' true
i = struct{}{}
b, ok = i.(interface{})
fmt.Printf(fm, b, ok) // 'struct {}' 'struct {}{}' '{}' true
i = fmt.Println
b, ok = i.(interface{})
fmt.Printf(fm, b, ok) // 'func(...interface {}) (int, error)' '(func(...interface {}) (int, error))(0x456740)' '0x456740' true
i = Shape.Area
b, ok = i.(interface{})
fmt.Printf(fm, b, ok) // 'func(main.Shape) float64' '(func(main.Shape) float64)(0x401910)' '0x401910' true
}
type Shape interface {
Area() float64
}
Common usecase: check if returned error is of a type T.
https://golang.org/ref/spec#Type_assertions
For a single return value assertion: when it fails the program panics.
For a two return values assertion: when it fails second argument is set to false and the program doesn't panic.
A type assertion is the x.(T) notation where x is of interface type and T is a type. Additionally, the actual value stored in x is of type T, and T must satisfy the interface type of x.

Method receivers ambiguity

Working on the go tour today. I noticed that I could pass struct literals to methods associated with pointer to structs, and vice versa. Why is this allowed?
package main
import (
"fmt"
)
type Vertex struct {
X, Y float64
}
func (v Vertex) Scale (f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
func (v *Vertex) ScaleP(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
func main() {
v := &Vertex{3, 4}
vLiteral := Vertex{3, 4}
v.Scale(5)
fmt.Println(v)
v.ScaleP(5)
fmt.Println(v)
vLiteral.Scale(5)
fmt.Println(vLiteral)
vLiteral.ScaleP(5)
fmt.Println(vLiteral)
}
Output:
&{3 4}
&{15 20}
{3 4}
{15 20}
See Method sets:
A type may have a method set associated with it (§Interface types, §Method declarations). The method set of an interface type is its interface. The method set of any other type T consists of all methods with receiver type T. The method set of the corresponding pointer type *T is the set of all methods with receiver *T or T (that is, it also contains the method set of T). Further rules apply to structs containing anonymous fields, as described in the section on struct types. Any other type has an empty method set. In a method set, each method must have a unique method name.
The method set of a type determines the interfaces that the type implements and the methods that can be called using a receiver of that type.
EDIT:
See also Calls:
A method call x.m() is valid if the method set of (the type of) x contains m and the argument list can be assigned to the parameter list of m. If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m():

Resources