Avoiding Go copying interface data - go

This is part of real world code I'm trying to write. The problem is that Go copies the interface sibling so I can't modify the data. However, if I change to using a pointer to an interface then the concept of equality fails. I know I can use DeapEquals, but not in a map.
package main
import (
"fmt"
)
type Q interface {
modify()
}
type P struct {
name string
sibling Q
}
func (x P) modify() {
x.name = "a"
}
func main() {
a := P{"a", nil}
A := P{"?", nil}
b := P{"b", a}
B := P{"b", A}
B.sibling.modify()
fmt.Println(B)
fmt.Println(b == B)
}
How do I get Go to let me modify the interface data itself without copying it and modifying the copy?
It seems these are mutually exclusive on a struct:
I need to be able to use maps
I need to be able to modify the interface data with methods

The only way to modify the data without copying it is to use pointers.
I'm a little confused by what you are saying as your example uses a struct and you talk about structs but then you say you need to be able to use maps. Either way, DeepReflect works with both. Here is your example modified to use pointers:
package main
import (
"fmt"
"reflect"
)
type Q interface {
modify()
}
type P struct {
name string
sibling Q
}
func (x *P) modify() {
x.name = "a"
}
func main() {
a := P{"a", nil}
A := P{"?", nil}
b := P{"b", &a}
B := P{"b", &A}
B.sibling.modify()
fmt.Println("a:", a)
fmt.Println("A:", A)
fmt.Println("b:", b)
fmt.Println("B:", B)
fmt.Println(b == B)
fmt.Println(reflect.DeepEqual(b, B))
}
Prints:
a: {a <nil>}
A: {a <nil>}
b: {b 0x10436180}
B: {b 0x10436190}
false
true
And you can see this post for doing the same with maps.

You can use value returned from modify()
package main
import (
"fmt"
)
type Q interface {
modify() Q //See here
}
type P struct {
name string
sibling Q
}
func (x P) modify() Q{ //Here
x.name = "a"
return x
}
func main() {
a := P{"a", nil}
A := P{"?", nil}
b := P{"b", a}
B := P{"b", A}
B.sibling=B.sibling.modify() //And here
fmt.Println(B)
fmt.Println(b == B)
}
It's verbose a bit, but at least works https://play.golang.org/p/8oM90wriN0

Related

Operate on a struct with lots of pointers (especially to numbers)

I have quite a few data structures that contain mostly numbers, I get the data, do a calculation and return the result.
The thing is that all of those numbers can be zero and hence, I had to switch to using pointers (*int64 or *float64) so that the default is nil and not 0.
Unfortunately, I don't know of a solution to this in Go except using pointers.
The problem comes now in the Calculate() function that is implemented for all data structures:
type X struct {
A, B, C, D, E, F *int
// and much more
Result *float64
}
func (x *X) Calculate() {
floatptr := func(f float64) *float64 { return &f }
x.Result = floatptr(float64(*x.A + *x.B + *x.C + *x.D + *x.E + *x.F))
}
This function will obviously panic if any of the data is nil. So, I wrote the functions differently that it checks for nil data before the calculation:
func (x *X) CalculateWithNilChecks() {
floatptr := func(f float64) *float64 { return &f }
if x.A == nil || x.B == nil || x.C == nil || x.D == nil || x.E == nil || x.F == nil {
return
}
x.Result = floatptr(float64(*x.A + *x.B + *x.C + *x.D + *x.E + *x.F))
}
The problem is that the data structures are quite long. Having a SUPER long if x != nil looks ugly. I was wondering if there is another (cleaner) way to doing this.
I thought of doing like in the encoding/json and just recover nil pointer dereference panics, not sure if this is cleaner TBH.
Another thought was to reflect the data structures and stop if any of the required data is nil, I don't think this should be necessary for such a simple task.
Here is a playground link for the above code
What am I missing here? Thanks!
As general solution you can unmarshal your JSON into a map of *int pointers or json.RawMessage and then use a reflection to cross check with your struct or just check it with expected number of fields.
func main() {
result := make(map[string]*int)
str := `{ "A": 1, "B": 2, "C": 3, "D": 4, "E": 5, "F": 6 }`
json.Unmarshal([]byte(str), &result)
for _, field := range result {
// Check if expect fields exists using reflection or manually
// ...
}
}
You can use reflect module and error when one of the required fields is missing.
Use this as template.
package main
import (
"fmt"
"reflect"
)
type X struct {
A, B, C, D, E, F *int
Result *float64
}
func (x *X) PrintFoo() {
fmt.Println(x.A)
}
func main() {
a := 3
x := X{A: &a}
val := reflect.ValueOf(x)
for i := 0; i < val.Type().NumField(); i++ {
field := val.Type().Field(i)
fieldType := fmt.Sprintf("%s", field.Type)
if fieldType == "*int" && val.FieldByName(field.Name).IsNil() {
fmt.Println("Missing value on field", field.Name)
}
}
}

Multiple implementation of the same method that might have differents dependencies with Go and Interfaces

I have a problem about using interfaces.
I have a Compute(a, b int) Method that has 2 implementations, depending on the receiver.
func (addition *Addition) Compute(a, b int) int{
return a+b
}
func (mult *Multiplication) Compute(a, b int) int{
return a*b
}
type myInterface{
Compute(a, b int) int
}
Let's imagine I need to call a webService in Multiplication to get the value of a.
Now we have:
func (mult *Multiplication) Compute(iface WSInterface, a, b int) int{
a := iface.getA()
return a*b
}
Now, I will need to add iface WSInterface into Compute() Interface definition, and add it to Addition, even if it doesn't need it.
I will end with:
type Addition struct{}
type Multiplication struct{}
func main() {
addition := &Addition{}
multiplication := &Multiplication{}
res1 := addition.Compute(nil, 1, 2)
res2 := addition.Compute(multiplication, 3, 4)
fmt.Print(res1, res2)
}
type WSInterface interface {
getA() int
}
func (mult *Multiplication) getA() int {
return 1 // Mocked
}
type myInterface interface {
Compute(iface myInterface, a, b int) int
}
func (addition *Addition) Compute(iface WSInterface, a, b int) int {
return a + b
}
func (mult *Multiplication) Compute(iface WSInterface, a, b int) int {
return iface.getA() * b
}
but in Addition, it will not be used.
In real life, you can have several dependencies to different microservices, and I find it not so elegant to define params that you will not use in your function. There must be something wrong here.
Is it ok to do this, is it a bad pattern, or how should I do to fix it ?
These special interfaces/objects should be passed in the constructor, keeping the interfaces themselves clean.
Something like:
type Multiplication struct {
iface otherInferface
// .. other Multiplication-specific fields
}
func NewMultiplication(iface otherInterface) *Multiplication {
return &Multiplication{iface: iface}
}
And then:
func (mult *Multiplication) Compute(a, b int) int{
a := mult.iface.getA()
return a*b
}
So your myInterface remains simple and clean:
type myInterface interface {
Compute(a, b int)
}

os.Read() How is work? Golang

Why if I print bs, before calling Read(), it prints nothing, but after the call file.Read(bs), it shows the inside of test.txt file. Unless bs is only argument, how Read() can Change it?
package main
import (
"os"
"fmt"
)
func main() {
file , err := os.Open("test.txt")
if err == nil {
} else {
}
stat , _ := file.Stat()
bs := make([]byte, stat.Size())
fmt.Println(string(bs))
bsf ,err := file.Read(bs)
if err != nil{
fmt.Println(err)
fmt.Println(bsf)
}
fmt.Println(string(bs))
}
Output:
(Line1)
(Line2)hi, This is Example text in test.txt file.
Unless bs is only argument, how Read() can Change it?
It seems that you may be missing basic knowledge about programming languages in general. There are different kind of "values". There are pointers (or references) and there are the "usual values".
For example:
package main
import (
"fmt"
)
func changeIt(p *int) {
*p = 9
}
func main() {
a := 1
fmt.Println(a)
changeIt(&a)
fmt.Println(a)
}
It'll print 1 9 not 1 1. *int is not an integer, but a pointer to an integer. A pointer is a value that points (references) another value. If you have a value of type pointer you get the actual value that the pointer points to by using * (which is called dereferencing):
func main() {
a := 1
b := &a
fmt.Println(b, *b)
}
b is a pointer (of type *int) that points to a. The println will print the location of a followed by the value of a which is usually something like uhm 0x10414020 1. We can also modify the value a pointer points to by using *p = ...:
func main() {
a := 1
b := &a
*b = 9
fmt.Println(b, *b, a)
}
which will print 0x10414020 9 9.
Now, []byte is a slice... slices are like pointers. When you do
func changeIt(buf []byte) {
buf[0] = 10
}
func main() {
data := []byte{1,2,3}
changeIt(data)
fmt.Println(data)
}
You're not actually passing the values [1 2 3] to changeIt but a pointer to those values. Thus here the println will show [10 2 3]. Compare this to:
func changeIt(buf [3]byte) {
buf[0] = 10
}
func main() {
data := [3]byte{1,2,3}
changeIt(data)
fmt.Println(data)
}
Which will print [1 2 3] and it will pass the values [1 2 3] and not a pointer so changeIt essentially works on a copy and the buf[0] = 10 has no effect. Remember: [n]T is an array, []T is a slice. [n]T is a "raw value" and []T is a "pointer value".

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.

invalid operation: s[k] (index of type *S)

I want to define a type like this:
type S map[string]interface{}
and I want add a method to the type like this:
func (s *S) Get( k string) (interface {}){
return s[k]
}
when the program runs, there was a error like this:
invalid operation: s[k] (index of type *S)
So, how do I define the type and add the method to the type?
For example,
package main
import "fmt"
type S map[string]interface{}
func (s *S) Get(k string) interface{} {
return (*s)[k]
}
func main() {
s := S{"t": int(42)}
fmt.Println(s)
t := s.Get("t")
fmt.Println(t)
}
Output:
map[t:42]
42
Maps are reference types, which contain a pointer to the underlying map, so you normally wouldn't need to use a pointer for s. I've added a (s S) Put method to emphasize the point. For example,
package main
import "fmt"
type S map[string]interface{}
func (s S) Get(k string) interface{} {
return s[k]
}
func (s S) Put(k string, v interface{}) {
s[k] = v
}
func main() {
s := S{"t": int(42)}
fmt.Println(s)
t := s.Get("t")
fmt.Println(t)
s.Put("K", "V")
fmt.Println(s)
}
Output:
map[t:42]
42
map[t:42 K:V]

Resources