Changing the value of a non-struct with a pointer receiver - go

If I have a type which is not a struct how do I change its value with a pointer receiver?
For example, given the following code:
package main
import (
"fmt"
)
type MyInt int
func (i *MyInt) Change() {
newValue := MyInt(32)
i = &newValue
}
func main() {
myInt := MyInt(64)
fmt.Println(myInt)
myInt.Change()
fmt.Println(myInt)
}
It outputs:
64
64
Why does it not output the following:
64
32
?

You're changing the value of the pointer i, not the value at which the pointer is pointing.
You will see your expected output by using the * operator:
*i = newValue
https://play.golang.org/p/mKsKC0lsj9

for your function define:
func (i *MyInt) Change() {
newValue := MyInt(32)
i = &newValue
}
when you call this function:
myInt := MyInt(64)
myInt.Change()
the value of myInt will pass to i, so after call func (i *MyInt) Change(), you only modify the i, not myInt.

Related

How to omit conditional field of struct within marshal

There is struct of MyStruct.
type MyStruct struct {
Code int `json:"Code"`
Flags uint8 `json:"Flags"`
OptionField int `json:",omitempty"`
}
Following code convert it to json.
f := MyStruct{Code:500, OptionField:41}
r, _ := json.Marshal(f)
fmt.Println(string(r)
I need to "OptionField" be optional. Some time it should exist in json with one of values [0, 1, 2, 3, ]. and in the other time it should exclude from json.
My problem is: omitempty will exclude it when the value is zero, and the default value of int is zero. Is there any way to omit field in condition (ex: omit if value is -1). Or there is any way to do it.
You could use *int instead of int and set the pointer value to nil in order to omit this.
package main
import (
"encoding/json"
"fmt"
)
type MyStruct struct {
Code int `json:"Code"`
Flags uint8 `json:"Flags"`
OptionField *int `json:",omitempty"`
}
func format(s MyStruct) string {
r, _ := json.Marshal(s)
return string(r)
}
func main() {
f := MyStruct{Code: 500, Flags: 10, OptionField: new(int)}
fmt.Println(format(f)) // {"Code":500,"Flags":10,"OptionField":0}
f.OptionField = nil
fmt.Println(format(f)) // {"Code":500,"Flags":10}
}

Create method to a slice type

I am new to golang. I am trying to add a method to a slice. The method is just a wrapper of append, which does not work.
package main
import (
"fmt"
)
type SliceStr []string
func (ss *SliceStr) Add(s string) {
ss = append(ss, s)
}
func main() {
var s SliceStr
s.Add("hello")
fmt.Println(s)
}
prog.go:10:12: first argument to append must be slice; have *SliceStr
You are getting a pointer to SliceStr (*SliceStr), not SliceStr and therefore not a slice-type. Just dereference the pointer
func (ss *SliceStr) Add(s string) {
*ss = append(*ss, s)
}
and it works just fine. *ss = ... sets the value ss is pointing to and the *ss in the call to append passes it the value ss is pointing to, instead of the pointer.

Looping over slice of aliased(user defined) types gives type before aliasing

I'm trying to loop over slice of user defined types (in example below these are aliased int), but range produces values of type int, instead of MyInt as I would expect. Casting inside 'if' helps for sure, but I would like to understand why range does not produces values of type MyInt.
package main
import (
"fmt"
)
type MyInt int
const (
MYINT00 MyInt = iota
MYINT01
)
func main() {
var myInt02 MyInt = 2
myInts := []MyInt{MYINT00, MYINT01}
for i := range myInts {
if i == myInt02 {
fmt.Println("same")
}
}
}
Playground: https://play.golang.org/p/nb77pvTMdkW
Error:
prog.go:18:8: invalid operation: i == myInt02 (mismatched types int and MyInt)
Then I thought that problem can be related to consts and iota, so I used variables declared in function - didn't change anything.
https://play.golang.org/p/0fVRhBtvlOL
https://play.golang.org/p/pioDSU4oJdP
I haven't found any info in Effective Go/other questions. If anybody has some input on that, please share!
The Go Programming Language Specification
For statements with range clause
Range expression 1st value 2nd value
array or slice a [n]E, *[n]E, or []E index i int a[i] E
i is the range index, an int, not the range value.
For example, fixing your code to use the range value,
package main
import (
"fmt"
)
type MyInt int
const (
MYINT00 MyInt = iota
MYINT01
)
func main() {
var myInt02 MyInt = 2
myInts := []MyInt{MYINT00, MYINT01}
for _, v := range myInts {
if v == myInt02 {
fmt.Println("same")
}
}
}

How do I declare a function pointer to a method in Go

I am trying to create function pointer to a function that has a method receiver. However, I can't figure out how to get it to work (if it is possible)?
Essentially, I have the following:
type Foo struct {...}
func (T Foo) Bar bool {
...
}
type BarFunc (Foo) func() bool // Does not work.
The last line of the code gives the error
syntax error: unexpected func, expecting semicolon or newline
If you want to create a function pointer to a method, you have two ways. The first is essentially turning a method with one argument into a function with two:
type Summable int
func (s Summable) Add(n int) int {
return s+n
}
var f func(s Summable, n int) int = (Summable).Add
// ...
fmt.Println(f(1, 2))
The second way will "bind" the value of s (at the time of evaluation) to the Summable receiver method Add, and then assign it to the variable f:
s := Summable(1)
var f func(n int) int = s.Add
fmt.Println(f(2))
Playground: http://play.golang.org/p/ctovxsFV2z.
Any changes to s after f is assigned will have no affect on the result: https://play.golang.org/p/UhPdYW5wUOP
And for an example more familiar to those of us used to a typedef in C for function pointers:
package main
import "fmt"
type DyadicMath func (int, int) int // your function pointer type
func doAdd(one int, two int) (ret int) {
ret = one + two;
return
}
func Work(input []int, addthis int, workfunc DyadicMath) {
for _, val := range input {
fmt.Println("--> ",workfunc(val, addthis))
}
}
func main() {
stuff := []int{ 1,2,3,4,5 }
Work(stuff,10,doAdd)
doMult := func (one int, two int) (ret int) {
ret = one * two;
return
}
Work(stuff,10,doMult)
}
https://play.golang.org/p/G5xzJXLexc
I am very likely off-target (just started on Golang) but what if you create a pointer then examine type:
pfun := Bar
fmt.Println("type of pfun is:", reflect.TypeOf(pfun))
then it seems that you can declare the type of pointer correctly:
https://play.golang.org/p/SV8W0J9JDuQ

Using function names as parameters

In Go, you can pass functions as parameters like callFunction(fn func). For example:
package main
import "fmt"
func example() {
fmt.Println("hello from example")
}
func callFunction(fn func) {
fn()
}
func main() {
callFunction(example)
}
But is it possible to call a function when it's a member of a struct? The following code would fail, but gives you an example of what I'm talking about:
package main
import "fmt"
type Example struct {
x int
y int
}
var example Example
func (e Example) StructFunction() {
fmt.Println("hello from example")
}
func callFunction(fn func) {
fn()
}
func main() {
callFunction(example.StructFunction)
}
(I know what I'm trying to do in that example is a little odd. The exact problem I have doesn't scale down to a simple example very well, but that's the essence of my problem. However I'm also intrigued about this from an academic perspective)
Methods (which are not "members of a struct" but methods of any named type, not only structs) are first class values. Go 1.0.3 didn't yet implemented method values but the tip version (as in the comming Go 1.1) has support method values. Quoting the full section here:
Method values
If the expression x has static type T and M is in the method set of type T, x.M is called a method value. The method value x.M is a function value that is callable with the same arguments as a method call of x.M. The expression x is evaluated and saved during the evaluation of the method value; the saved copy is then used as the receiver in any calls, which may be executed later.
The type T may be an interface or non-interface type.
As in the discussion of method expressions above, consider a struct type T with two methods, Mv, whose receiver is of type T, and Mp, whose receiver is of type *T.
type T struct {
a int
}
func (tv T) Mv(a int) int { return 0 } // value receiver
func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver
var t T
var pt *T
func makeT() T
The expression
t.Mv
yields a function value of type
func(int) int
These two invocations are equivalent:
t.Mv(7)
f := t.Mv; f(7)
Similarly, the expression
pt.Mp
yields a function value of type
func(float32) float32
As with selectors, a reference to a non-interface method with a value receiver using a pointer will automatically dereference that pointer: pt.Mv is equivalent to (*pt).Mv.
As with method calls, a reference to a non-interface method with a pointer receiver using an addressable value will automatically take the address of that value: t.Mv is equivalent to (&t).Mv.
f := t.Mv; f(7) // like t.Mv(7)
f := pt.Mp; f(7) // like pt.Mp(7)
f := pt.Mv; f(7) // like (*pt).Mv(7)
f := t.Mp; f(7) // like (&t).Mp(7)
f := makeT().Mp // invalid: result of makeT() is not addressable
Although the examples above use non-interface types, it is also legal to create a method value from a value of interface type.
var i interface { M(int) } = myVal
f := i.M; f(7) // like i.M(7)
Go 1.0 does not support the use of bound methods as function values. It will be supported in Go 1.1, but until then you can get similar behaviour through a closure. For example:
func main() {
callFunction(func() { example.StructFunction() })
}
It isn't quite as convenient, since you end up duplicating the function prototype but should do the trick.
I fixed your compile errors.
package main
import "fmt"
type Example struct {
x, y float64
}
var example Example
func (e Example) StructFunction() {
fmt.Println("hello from example")
}
func callFunction(fn func()) {
fn()
}
func main() {
callFunction(example.StructFunction)
}
Output:
hello from example
To add to #zzzz great answer (and the one given at https://golang.org/ref/spec#Method_values) here is an example that creates a method value from a value of an interface type.
package main
import "fmt"
type T struct{}
func (T) M(i int) { fmt.Println(i) }
func main() {
myVal := T{}
var i interface{ M(int) } = myVal
f := i.M
f(7) // like i.M(7)
}

Resources