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.
Related
If I use pointer receiver, the following code has exception at a=v since it is defined on pointer v, it makes sense.
package main
import (
"fmt"
"math"
)
type Abser interface {
Abs(x int) float64 //all types needs to implement this interface
}
type Vertex struct {
X float64
}
func (v *Vertex) Abs(x int) float64 {
return math.Abs(float64(x))
}
func main() {
/*define the interface and assign to it*/
var a Abser
v := Vertex{-3}
a = &v
fmt.Println(a.Abs(-3))
a = v
fmt.Println(a.Abs(-3))
}
But if I change the function of Abs to
func (v Vertex) Abs(x int) float64 {
return math.Abs(float64(x))
}
both a=v and a=&v works, what is the reason behind that?
Understand it like this as I do not have right resources to quote in answer; Go is happy to pass a copy of pointer struct as value when interface is implemented on value, you can check this by printing the address of variable; This is due to the fact that this operation is considered safe and cannot mutate the original value;
I'm learning go and came across this piece of code on go tour:
package main
import (
"fmt"
"math"
)
type MyFloat int
func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
func (f MyFloat) run() string{
fmt.Println("This is called")
return "Hey there"
}
func main() {
f := MyFloat(-math.Sqrt2)
fmt.Println(f.Abs())
fmt.Println(f.run())
}
Here we declare a type named MyFloat and return type is float64. I was thinking that I can declare methods which only returns float64. I declared a method named run() in the above case which returns string. How is this possible? Why can't I just declare the type with no specific return type like this type MyFloat?
Example in Playground
You are confusing types and methods. As putu already menitioned in a comment, types don't "return" anything. In a kind of handwavy way most types are just data structures that you can attach methods to*.
Another way to write the methods in your example is this:
// func (f MyFloat) Abs() float64 {
func Abs(f MyFloat) float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
// func (f MyFloat) run() string {
func run(f MyFloat) string {
fmt.Println("This is called")
return "Hey there"
}
Note that the function bodies are no different at all. The difference is just in how you call these functions. Semantically they are equivalent. The receiver of a method becomes the implicit first argument to a function.
[*] This ignores function types, which don't hold data. net/http.HandlerFunc is a prominent example in the standard library.
type HandlerFunc func(ResponseWriter, *Request)
Is there anyway to make a map of function pointers, but functions that take recievers? I know how to do it with regular functions:
package main
func someFunc(x int) int {
return x
}
func main() {
m := make(map[string]func(int)int, 0)
m["1"] = someFunc
print(m["1"](56))
}
But can you do that with functions that take recievers? Something like this (though I've tried this and it doesn't work):
package main
type someStruct struct {
x int
}
func (s someStruct) someFunc() int {
return s.x
}
func main() {
m := make(map[string](someStruct)func()int, 0)
s := someStruct{56}
m["1"] = someFunc
print(s.m["1"]())
}
An obvious work around is to just pass the struct as a parameter, but that's a little dirtier than I would have liked
You can do that using Method Expressions:
https://golang.org/ref/spec#Method_expressions
The call is a bit different, since the method expression takes the receiver as the first argument.
Here's your example modified:
package main
type someStruct struct {
x int
}
func (s someStruct) someFunc() int {
return s.x
}
func main() {
m := make(map[string]func(someStruct)int, 0)
s := someStruct{56}
m["1"] = (someStruct).someFunc
print(m["1"](s))
}
And here's a Go playground for you to test it:
https://play.golang.org/p/PLi5A9of-U
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.
I have following code:
package main
import (
"fmt"
)
type Point struct {
x,y int
}
func decode(value interface{}) {
fmt.Println(value) // -> &{0,0}
// This is simplified example, instead of value of Point type, there
// can be value of any type.
value = &Point{10,10}
}
func main() {
var p = new(Point)
decode(p)
fmt.Printf("x=%d, y=%d", p.x, p.y) // -> x=0, y=0, expected x=10, y=10
}
I want to set value of any type to the value passed to decode function. Is it possible in Go, or I misunderstand something?
http://play.golang.org/p/AjZHW54vEa
Generically, only using reflection:
package main
import (
"fmt"
"reflect"
)
type Point struct {
x, y int
}
func decode(value interface{}) {
v := reflect.ValueOf(value)
for v.Kind() == reflect.Ptr {
v = v.Elem()
}
n := reflect.ValueOf(Point{10, 10})
v.Set(n)
}
func main() {
var p = new(Point)
decode(p)
fmt.Printf("x=%d, y=%d", p.x, p.y)
}
I'm not sure of your exact goal.
If you want to assert that value is a pointer to Point and change it, you can do that :
func decode(value interface{}) {
p := value.(*Point)
p.x=10
p.y=10
}