Here is my code:
type Cake struct {
weight int
value int
costBenefit float32
}
func (c *Cake) SetCostBenefit() float32 {
if c.costBenefit == 0 {
c.costBenefit = float32(c.value) / float32(c.weight)
}
return c.costBenefit
}
func main() {
capacity := 20
cakes := []Cake{{weight: 7, value: 160}, {weight: 3, value: 90}, {weight: 2, value: 15}}
result := maxDuffelBagValue(cakes, capacity)
fmt.Printf("Max capacity %d", result)
}
func maxDuffelBagValue(cakes []Cake, capacity int) int {
calcCostBenefit(&cakes)
for _, c := range cakes {
fmt.Printf("Value Cake cost benefit 2: %v \n", c.costBenefit)
}
return 0
}
func calcCostBenefit(cakes *[]Cake) {
for _, c := range *cakes {
c.SetCostBenefit()
fmt.Printf("Value Cake cost benefit 1: %v \n", c.costBenefit)
}
}
As you can see above, I have a struct method that sets the CostBenefit property of the struct Cake. As I'm sending the array of cakes to the method calcCostBenefit, any change within the method should reflect the array in the outside (caller method). But actually, it doesn't happen. Here's the output:
Value Cake cost benefit 1: 22.857143
Value Cake cost benefit 1: 30
Value Cake cost benefit 1: 7.5
Value Cake cost benefit 2: 0
Value Cake cost benefit 2: 0
Value Cake cost benefit 2: 0
The values get reset to zero and I don't know why. I've tried several changes in the code, but nothing worked. What am I missing here? It's driving me crazy nothing being able to spot something that might be so obvious and simple.
In the provided example, the for range
loop copies the value(s) of the underlying slice
's array
item into a new variable (c
) — which is subsequently printed out in your example at:
fmt.Printf("Value Cake cost benefit 1: %v \n", c.costBenefit)
You can obtain a pointer to an entry in the slice
by using c := &cakes[i]
. Note the difference between slice
s and array
s, particularly that when slice
s are copied, the underlying array
remains the same:
... As mentioned earlier, re-slicing a slice doesn't make a copy of the underlying array. The full array will be kept in memory until it is no longer referenced. Occasionally this can cause the program to hold all the data in memory when only a small piece of it is needed. ...
https://blog.golang.org/slices-intro#TOC_6.
Thus, there's need to pass the slice
by reference if you're only attempting to change the underlying values in the array, referenced by the slice
.
So, this:
func maxDuffelBagValue(cakes []Cake, capacity int) int {
calcCostBenefit(&cakes)
for _, c := range cakes {
fmt.Printf("Value Cake cost benefit 2: %v \n", c.costBenefit)
}
return 0
}
func calcCostBenefit(cakes *[]Cake) {
for _, c := range *cakes {
c.SetCostBenefit()
fmt.Printf("Value Cake cost benefit 1: %v \n", c.costBenefit)
}
}
Becomes this:
func maxDuffelBagValue(cakes []Cake, capacity int) int {
calcCostBenefit(cakes)
for _, c := range cakes {
fmt.Printf("Value Cake cost benefit 2: %f \n", c.costBenefit)
}
return 0
}
func calcCostBenefit(cakes []Cake) {
for i, _ := range cakes {
c := &cakes[i]
c.SetCostBenefit()
fmt.Printf("Value Cake cost benefit 1: %v \n", c.costBenefit)
}
}
Output:
Value Cake cost benefit 1: 22.857143
Value Cake cost benefit 1: 30
Value Cake cost benefit 1: 7.5
Value Cake cost benefit 2: 22.857143
Value Cake cost benefit 2: 30.000000
Value Cake cost benefit 2: 7.500000
NB
The following also works:
func calcCostBenefit(cakes *[]Cake) {
for idx, _ := range *cakes {
c := &(*cakes)[idx]
c.SetCostBenefit()
fmt.Printf("Value Cake cost benefit 1: %v \n", c.costBenefit)
}
}
... but it's more complicated given the alternative above. Nevertheless, this may be required if you're not able to change method signatures for whatever reason (external packages).
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments