I have problems understanding methods and receivers in Go. Let's say we have this code:
package main
import ("fmt"; "math")
type Circle struct {
x, y, r float64
}
func (c *Circle) area() float64 {
return math.Pi * c.r * c.r
}
func main() {
c := Circle{0, 0, 5}
fmt.Println(c.area())
}
(c *Circle) in the definition of the area function is said to be a receiver and in the main we can call area and pass c by reference without the use of pointers. I can edit the code to the following and it works the same way:
package main
import ("fmt"; "math")
type Circle struct {
x, y, r float64
}
func circleArea(c *Circle) float64 {
return math.Pi * c.r*c.r
}
func main() {
c := Circle{0, 0, 5}
fmt.Println(circleArea(&c))
}
Now is this just a syntactical difference between the two snippets of code or is there something structurally different going on on a deeper level?
The difference isn't just syntax. With a method, your circle type could fulfill an interface, but the function doesn't let you do that:
type areaer interface {
area() float64
}
Related
Why assigning a method to function handler works.
shortlink: https://play.golang.org/p/UEYGCpMgyV6
package main
import (
"fmt"
"math"
)
type Vertex struct {
X, Y float64
}
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func Abs() float64 {
return math.Sqrt(10)
}
func AbsFloat(f float64) float64 {
return math.Sqrt(f)
}
func main() {
v := Vertex{3, 4}
// Assigning Abs() to func handler.
var absFunc func() float64 = Abs
fmt.Println(absFunc())
// Wrong type as expected.
//absFunc = AbsFloat
// Assigning method to func handler works, why ?
absFunc = v.Abs
// Changing receiver args. Useful for unittesting but why/how this works ?
v.X = 1
v.Y = 1
fmt.Println(absFunc())
}
Is it a Golang type checking 'feature' that func()float64 == func(T)float64 or something else ? Please help to understand this concept.
v.Abs is a method value, and quoting from the spec:
The method value x.M is a function value that is callable with the same arguments as a method call of x.M.
A method value has a function type with identical parameter and result types as the method without the receiver.
i am using following code...
package main
import (
"fmt"
)
type traingle interface {
area() int
}
type details struct {
height int
base int
}
func (a details) area() int {
s := a.height + a.base
fmt.Println("the area is", s)
return s
}
func main() {
r := details{height: 3, base: 4}
var p1 traingle
p1.area(r)
}
not getting why getting following error
too many arguments in call to p1.area
have (details)
want ()
i am assuming that p1 object of triangle can call area() method with arguments. not getting why it is failing.
The function area takes no arguments in its definition:
area() int
// ...
func (a details) area() int {
Therefor, passing any arguments to it is, as the error says, too many arguments. There is nowhere in the function where it makes use of arguments. It's making all its calculations based on the properties of its receiver, not any arguments. You're also calling it on an uninitialized (nil) interface value. It looks like what you want is probably:
r := details{height: 3, base: 4}
r.area()
Try this:
package main
import (
"fmt"
)
type shape interface {
area() int
}
type traingle struct {
height int
base int
}
func (a traingle) area() int {
return a.height * a.base / 2
}
func main() {
var p1 shape = traingle{height: 3, base: 4}
fmt.Println(p1.area())
}
output:
6
And see this example on shape: https://stackoverflow.com/a/38818437/8208215
I hope this helps.
I can't figure out how to create a package and use it. I'm using liteid and go 1.4.2 but this is all reproduce-able from the command-line. I' able to create the shape package it seems but it doesn't load from the main package.
GOPATH=d:\src\teaching\golang
GOROOT=c:\go
+teaching\golang\pkg
\windows_386
shape.a
\src
\packages
packages.go
\shape
shape.go
go install shape -> generates shape.a
go build packages.go
# packages
d:\src\teaching\golang\src\packages\packages.go:5: imported and not used: "shape"
d:\src\teaching\golang\src\packages\packages.go:8: undefined: Shape
d:\src\teaching\golang\src\packages\packages.go:19: undefined: Circle
shape.go
package shape
import (
"fmt"
)
const (
pi = float64(3.14)
)
type Shape interface {
Area() float64
}
type Circle struct {
x int
y int
radius int
}
func (c *Circle) Area() float64 {
return pi * float64(c.radius*c.radius)
}
func (c Circle) String() string {
return fmt.Sprintf("{x=%d, y=%d, radius=%d}", c.x, c.y, c.radius)
}
packages.go
package main
import (
"fmt"
"shape"
)
func calculateArea(shapes ...Shape) float64 {
sum := float64(0)
for _, v := range shapes {
sum += v.Area()
}
return sum
}
func main() {
circle := Circle{x: 1, y: 2, radius: 2}
fmt.Println(circle, circle.Area(), calculateArea(&circle))
}
Any ideas?
Shape is defined in the shape package. You have to reference it as shape.Shape
How to realize "Virtual Inheritance" in Go?
go lang compiler version: "1.3.1 windows/amd64", does it support "Virtual Inheritance" for Go?
I never heard a C like language could support "Virtual", so I really misunderstand.
Virtual Inheritance solves a problem which does not exist if you don't have multiple inheritance. Consider the following inheritance tree:
A
/ \
B C
\ /
D
If classes B and C both provide a data-member (or method for that matter) with the same name then when accessing said member in D, you need a way to disambiguate whose ancestor's data-member (or method) you wish to access.
Virtual Inheritance is C++'s solution.
In Go you don't have inheritance to begin with; only composition and you can embed at most 1 member of any given type at once.
http://play.golang.org/p/1iYzdoFqIC
package main
type B struct {
}
func (b B) Foo() {}
type C struct {
}
func (c C) Foo() {}
type D struct {
B
C
}
func main() {
d := D{B{}, C{}}
// d.Foo() // <- ambiguous
d.B.Foo() // <- ok
d.C.Foo() // <- ok
}
Virtual Inheritance not only solves the problem of multiple inheritance but also gives us polymorphism.
package main
import (
"fmt"
"math"
)
type Form interface {
Color() string
Area() float64
}
type form struct {
color string
}
func (f *form) Color() string {
return f.color
}
type Circle struct {
form
radius float64
}
func (k *Circle) Area() float64 {
return math.Pi * k.radius * k.radius
}
type Rectangle struct {
form
width, height float64
}
func (r *Rectangle) Area() float64 {
return r.width * r.height
}
func main() {
var forms [2]Form
forms[0] = &Circle{
form: form{ "black" },
radius: 5.0,
}
forms[1] = &Rectangle{
form: form{ "read" },
width: 2.0,
height: 3.0,
}
for _, f := range forms {
fmt.Printf("%s: %.2f\n", f.Color(), f.Area())
}
}
Here we have an array of things that have something in common (Color and Area) and we can just iterate over this array calling the same functions and always the right thing will happen.
This is just one advantage of polymorphism. It plays a big role in most design patterns.
"Virtual Inheritance" is something more like this
http://play.golang.org/p/8RvPmB3Pof
package main
type A struct {
virtual int
}
func (a *A) set(v int) {
a.virtual = v
}
func (a *A) get() int {
return a.virtual
}
type B struct {
*A
}
type C struct {
*A
}
type D struct {
*B
*C
}
func main() {
a := &A{}
b := &B{a}
c := &C{a}
d := &D{b, c}
d.B.set(3)
println(d.C.get())
return
}
Given the setup in the 54th slide of the golang tour:
type Abser interface {
Abs() float64
}
type Vertex struct {
X, Y float64
}
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
Why can't a method also be defined for the struct as well as the pointer to the struct? That is:
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
Defining this gives the following error:
prog.go:41: method redeclared: Vertex.Abs
method(*Vertex) func() float64
method(Vertex) func() float64
It can. Just define it on the struct and not the pointer. It will resolve both ways
Method Sets
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)
Try live: http://play.golang.org/p/PsNUerVyqp
package main
import (
"fmt"
"math"
)
type Abser interface {
Abs() float64
}
type Vertex struct {
X, Y float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := Vertex{5, 10}
v_ptr := &v
fmt.Println(v.Abs())
fmt.Println(v_ptr.Abs())
}
Update: As per comments I have created an extra example that actually makes use of the Abser interface to illustrate that both the value and the pointer satisfy the interface.
https://play.golang.org/p/Mls0d7_l4_t
While considering for example:
type T U
func (t *T) M() int { return 1 }
var t T
...we can now invoke M() on t by writing t.M() as the language permits to call a method with a pointer receiver even on its underlying (non pointer) typed instances, i.e. it becomes equivalent to (&t).M().
If it will be permitted to now additionaly define:
func (t T) M() int { return 2 }
...then there's no way to tell what is now t.M() supposed to return.