Why both these destroy functions do not change pointer to nil and how can I create such function?
package main
import (
"fmt"
)
type position struct {
x int
y int
}
func (p *position) destroy() {
p = nil
}
func destroy(p *position) {
p = nil
}
func main() {
p1 := &position{1,1}
p2 := &position{2,2}
p1.destroy()
destroy(p2)
if p1 == nil {
fmt.Println("p1 == nil")
} else {
fmt.Println(p1)
}
if p2 == nil {
fmt.Println("p2 == nil")
} else {
fmt.Println(p2)
}
}
Outputs:
&{1 1}
&{2 2}
https://play.golang.org/p/BmZjX1Hw24u
You need a pointer to pointer to change a pointer's value.
Here's your code sample, modified to do this (playground):
package main
import (
"fmt"
)
type position struct {
x int
y int
}
func destroy(p **position) {
*p = nil
}
func main() {
p1 := &position{1, 1}
destroy(&p1)
if p1 == nil {
fmt.Println("p1 == nil")
} else {
fmt.Println(p1)
}
}
In your current code
func destroy(p *position) {
p = nil
}
Inside destroy, p is a value the holds the address of a position struct. By assigning something to p itself, you're simply making it hold the address of some other position struct (or nil). You're not modifying the original pointer passed in.
This isn't different from a function trying to modify its argument by assigning to it:
// This will not actually modify the argument passed in by the caller
func setto2(value int) {
value = 2
}
The go spec says, in the section about calls and call parameters:
After they are evaluated, the parameters of the call are passed by
value to the function and the called function begins execution. The
return parameters of the function are passed by value back to the
calling function when the function returns.
Related
I am writing a program which has several structs and functions to handle these structs differently. I am having a generic function which calls the required function based on the inputs. Is there a generic way to use the returned value from getStruct()?
package main
var X func(s []string) A
var Y func(s []string) B
type A struct {
Name string
Place string
}
type B struct {
Name string
Place string
Value string
}
func newA(s []string) A {
a := A{
Name: s[0],
Place: s[1],
}
return a
}
func newB(s []string) B {
a := B{
Name: s[0],
Place: s[1],
Value: s[2],
}
return a
}
func getStruct(t string) interface{} {
switch {
case t == "A":
return X
case t == "B":
return Y
default:
return //someStruct
}
}
func main() {
buildNewStruct := getStruct("A") //Lets assume "A" here is got as an argument
var strSlice = []string{"Bob", "US"}
buildNewStruct(strSlice) //How to do this operation?
//I am hoping to use buildNewStruct(strSlice) to dynamically call
//either of newA(strSlice) or newB(strSlice) function
}
I have tried looking at this and this the later is not exactly the same as my question.
Since I am new to go, I am not sure if something like this is possible.
you can use the reflect package to set the struct properties to the equivalent index positioned value from an []interface{} slice.
package main
import (
"fmt"
"log"
"reflect"
)
func main() {
var a A
err := decode(&a, []interface{}{"Name", "Place"})
log.Println(err)
log.Println(a)
}
func decode(dst interface{}, values []interface{}) error {
rvptr := reflect.ValueOf(dst)
if rvptr.Kind() != reflect.Ptr {
return fmt.Errorf("value must be ptr")
}
rv := rvptr.Elem()
if rv.NumField() < len(values) {
return fmt.Errorf("too many values")
}
if rv.NumField() > len(values) {
return fmt.Errorf("too few values")
}
rvalues := reflect.ValueOf(values)
for i := range values {
f := rv.FieldByIndex([]int{i})
f.Set(rvalues.Index(i).Elem())
}
return nil
}
type A struct {
Name string
Place string
}
type B struct {
Name string
Place string
Value string
}
prints
$ go run main.go
2019/11/21 17:00:17 <nil>
2019/11/21 17:00:17 {Name Place}
The problem is the return type for the function.
func newA(in []string) interface{} {...}
func newB(in []string) interface{} {...}
func getStruct(name string) func([]string) interface{} {
switch name {
case "A": return newA
case "B": return newB
}
return nil
}
func main() {
buildNewStruct := getStruct("A")
var strSlice = []string{"Bob", "US"}
str:=buildNewStruct(strSlice)
if a, ok:=str.(A); ok {
...
}
}
With this approach, even though you saved some code by calling a unified buildNewStruct(), you have to use type assertions to figure out what is returned from that function, so this may not make a lot of sense. It depends on your exact use case though.
I'm still in the "wrestling with the language" stage of my Go progress, so forgive me for almost definitely missing something very obvious here.
I'm defining two structs, one containing the other. I make an array of the outer structs, pass it to a function, which calls a method on each of the inner structs, modifying their contents. This change is visible within the function, but when adding the outer structs to an array for returning, the outer function can't see the changes. I've tried throwing pointers in everywhere to little avail - somewhat thankfully, because it looked awful.
package main
import "github.com/davecgh/go-spew/spew"
type inner struct {
ints []int
}
func (i *inner) grow() {
i.ints = append(i.ints, 0)
}
type outer struct {
inner inner
}
func growOs(os []outer) (out []outer) {
for _, o := range os {
o.inner.grow()
out = append(out, o)
}
spew.Dump("----------during")
spew.Dump(out)
return
}
func main() {
os := []outer{
outer{},
outer{},
}
spew.Dump("----------pre")
spew.Dump(os)
growOs(os)
spew.Dump("----------post")
spew.Dump(os)
}
The o in your loop is a copy, so you either have to:
Change your slice to be []*outer.
Simply use a pointer to each item and modify the items in place.
Ex:
for i := range os {
o := &os[i]
o.inner.grow()
// or just os[i].inner.grow()
}
return os
just assign use the returned slice: os = growOs(os)
You should change
func main() {
os := []outer{
outer{},
outer{},
}
spew.Dump("----------pre")
spew.Dump(os)
growOs(os)
spew.Dump("----------post")
spew.Dump(os)
}
to
func main() {
os := []outer{
outer{},
outer{},
}
spew.Dump("----------pre")
spew.Dump(os)
os = growOs(os)
spew.Dump("----------post")
spew.Dump(os)
}
NOTICE: os = growOs(os)
in function
func growOs(os []outer) (out []outer) {
for _, o := range os {
o.inner.grow()
out = append(out, o)
}
spew.Dump("----------during")
spew.Dump(out)
return
}
you just return a new slice out, you don't modify the input slice os,
So in your main function, the os isn't changed.
Pointer argument vs value argument
If a function expects pointer argument it will obtain a pointer to an object thereby each change executed upon the object will have effect on the object itself. If a function expects a value argument it will obtain a copy of an object so each operation will affect an obtained copy not the object.
func recPointer(s *string) {
fmt.Printf("%p\n", s) // The same object
}
func recValue(s string) {
fmt.Printf("%p\n", &s) // A new object
}
func main() {
s := "asdf"
fmt.Printf("%p\n", &s)
recPointer(&s)
recValue(s)
}
Named return values
Go's return values may be named. If so, they are treated as variables defined at the top of the function.
Thereby it becomes clear that named return values are defined in function not in a name space above it. So when you return a named value you do it with a new object (again).
func recValue(s []string) (out []string) {
fmt.Printf("%p\n", &s) // A new object
out = append(out, s...)
// Again new object. It is not the `s` from `main`
// and obviously not the `s` var from incoming arguments.
fmt.Printf("%p\n", &out)
return
}
func main() {
s := []string{"asdf"}
fmt.Printf("%p\n", &s)
recValue(s)
}
Fixed example
Be careful! I replaced spew.Dump with fmt.Printf for demonstrative debug.
// No named return values
// Pointer argument receiver
func growOs(os *[]outer) *[]outer {
for _, o := range *os {
o.inner.grow()
*os = append(*os, o)
}
fmt.Printf("%p: %+v \n", os, os)
return os
}
func main() {
// `os` is a pointer to the object
os := &[]outer{
outer{},
outer{},
}
fmt.Printf("%p: %+v \n", os, os)
growOs(os)
fmt.Printf("%p: %+v \n", os, os)
}
I have a program where many functionalities are similar across different structures, however, I end up writing these functions again and again, esp because the variable that are being dealt inside are of different structures.
I have written a sample code here.
In Go Playgroud
package main
import "fmt"
func (a *Match) Add(v Match) {
a.Runs += v.Runs
a.Points += v.Points
}
type Match struct {
Runs uint64
Points uint64
}
func (a *Activity) Add(v Activity) {
a.Walk += v.Walk
a.Jog += v.Jog
}
type Activity struct {
Walk uint64
Jog uint64
}
func GetDailyMatches() map[string]Match {
var dailyMatches map[string]Match
Match1, Match2 := Match{5, 10}, Match{1, 2}
dailyMatches = make(map[string]Match)
dailyMatches["01"] = Match1
dailyMatches["02"] = Match2
dailyMatches["03"] = Match1
dailyMatches["04"] = Match2
return dailyMatches
}
func GetDailyActivities() map[string]Activity {
var dailyActivities map[string]Activity
Activity1, Activity2 := Activity{5, 10}, Activity{1, 2}
dailyActivities = make(map[string]Activity)
dailyActivities["01"] = Activity1
dailyActivities["02"] = Activity2
dailyActivities["03"] = Activity1
dailyActivities["04"] = Activity2
return dailyActivities
}
func main() {
fmt.Println(CalculateMatchSummary("01", "03"))
fmt.Println(CalculateActivitySummary("02", "04"))
fmt.Println(CalculateMatchSummary("01", "03"))
fmt.Println(CalculateActivitySummary("02", "04"))
}
func CalculateMatchSummary(start, end string) (total Match) {
dailyMatches := GetDailyMatches()
for day, value := range dailyMatches {
if day < start {
continue
} else if day > end {
continue
} else {
total.Add(value)
}
}
return
}
func CalculateActivitySummary(start, end string) (total Activity) {
dailyActivities := GetDailyActivities()
for day, value := range dailyActivities {
if day < start {
continue
} else if day > end {
continue
} else {
total.Add(value)
}
}
return
}
If you notice, both Match and Activity has the same functions and same structures, except that internally they are of different structures.
Is there a easy way to make the code more generic (Go generics, which is not there in Go??) in Golang itself.
Go has a pretty package "reflect". You can not do genericity strictly speaking but you can get unification of code for the same behavior.
I've changed your playground a bit : https://play.golang.org/p/bfqZsFOgVQ
The main part :
func AddTwo(a, b interface{}) interface{} {
va := reflect.ValueOf(a)
vb := reflect.ValueOf(b)
res := reflect.New(reflect.TypeOf(a)).Elem()
if va.Kind() != reflect.Struct && vb.Kind() != reflect.Struct {
return nil
}
na, nb := va.NumField(), vb.NumField()
if na != nb {
return nil
}
for i := 0; i < na; i++ {
// additional verification needed here
fa := va.Field(i).Uint()
fb := vb.Field(i).Uint()
fr := fa + fb
res.Field(i).SetUint(fr)
}
return res.Interface()
}
I use reflect to check the fields of the struct I am given. If both are uint64, I can add them reflectively. If your structs contains many uint64, it can add them all !
Note that you must convert the resulting interface to the type of the struct given after calling this function. That is why this is not strictly generic, because the returning type is a interface, and not a Match or Activity.
EDIT: No need even to return a new struct. You can simply update the field of the "a" struct by calling .SetUint() method.
I tried to make Trie data structures by Go Language, but somehow it stuck with References problem,
Here it is. http://play.golang.org/p/ASSGF5Oe9R
// Package main provides ...
package main
import "fmt"
type RootTrie []Trie
type Trie struct {
subtrie []Trie
index byte
}
func (trie *Trie) Insert(data string) *Trie {
if data != "" {
if trie.index == 0 {
trie.index = data[0]
}
if next := trie.containsIndex(data[1:]); next != nil {
//Problem Point
fmt.Println(string(data[1]), "found follwing", string(data[0]))
next.Insert(data[1:])
} else {
nt := &Trie{}
trie.subtrie = append(trie.subtrie, *nt.Insert(data[1:]))
}
}
return trie
}
func (trie *Trie) containsIndex(next string) *Trie {
if next != "" {
for _, st := range trie.subtrie {
if st.index == next[0] {
return &st
}
}
}
return nil
}
func main() {
t := &Trie{}
t = t.Insert("hanyang")
fmt.Println("result:", t)
t = t.Insert("hanyKk")
fmt.Println("result:", t)
t.Insert("hanyK")
}
The following problems happen in second "Insert",
the where I put, //Problem Point
I made containsIndex method for searching next linked trie, and it searched well actually.
But when I updated next property which containsIndex given, its not affected its mother struct trie though.
What I don't understand is I gave it reference type when returning containsIndex, but its still
act liked 'value copied', Why does it not affected its mother structure(trie)?
Thanks!
The problem is in method containsIndex. Golang range by default creates copy each element in slice and assigns copy of this value to st (in your example). Usually to preserve reference to element in slice you should use original slice and its index. In you case method containsIndex should look something like this:
func (trie *Trie) containsIndex(next string) *Trie {
if next != "" {
for i, st := range trie.subtrie {
if st.index == next[0] {
return &trie.subtrie[i]
}
}
}
return nil
}
I was expecting to see 3, what's going on?
package main
import "fmt"
type Counter struct {
count int
}
func (self Counter) currentValue() int {
return self.count
}
func (self Counter) increment() {
self.count++
}
func main() {
counter := Counter{1}
counter.increment()
counter.increment()
fmt.Printf("current value %d", counter.currentValue())
}
http://play.golang.org/p/r3csfrD53A
Your method receiver is a struct value, which means the receiver gets a copy of the struct when invoked, therefore it's incrementing the copy and your original isn't updated.
To see the updates, put your method on a struct pointer instead.
func (self *Counter) increment() {
self.count++
}
Now self is a pointer to your counter variable, and so it'll update its value.
http://play.golang.org/p/h5dJ3e5YBC
I want to add to #user1106925 response.
If you need to use the custom type inside a map you need to use a map to pointer. because the for l,v :=range yourMapType will receive a copy of the struct.
Here a sample:
package main
import "fmt"
type Counter struct {
Count int
}
func (s *Counter) Increment() {
s.Count++
}
func main() {
// Using map to type
m := map[string]Counter{
"A": Counter{},
}
for _, v := range m {
v.Increment()
}
fmt.Printf("A: %v\n", m["A"].Count)
// Now using map to pointer
mp := map[string]*Counter{
"B": &Counter{},
}
for _, v := range mp {
v.Increment()
}
fmt.Printf("B: %v\n", mp["B"].Count)
}
The output is:
$ go build && ./gotest
A: 0
B: 1