1

http://openmymind.net/Things-I-Wish-Someone-Had-Told-Me-About-Go/

Trying to get my head around Go, still pretty new. I know refs and pointers in C and I can't seem to get it working in Go. I've read a number of articles on the issue, and still not really managing to understand and implement a solution.

Characters have health and atk points.

Chars can Attack().

Combat round calls Attack() on which Character can attack this round.

Intent, when Attack() is called on Character, health is changed on another Character.

Currently Health never changes on Characters.

Can someone give me a concise example of how to change the values on objects around the RIGHT way?

package main

import (
    "fmt"
    "math/rand"
    "time"
)

//Character health + atk of
type Character struct {
    Health, Atk int
}

//Attack ... Character can Attack
func (c *Character) Attack(health, atk int) {
    health -= atk
}

//CharacterInterface ... methods for characters
type CharacterInterface interface {
    Attack(health, atk int)
}

func combatRound(p, e Character) {
    whoAtks := rand.Intn(100)
    if whoAtks > 30 {
        p.Attack(e.Health, p.Atk)
        fmt.Println(p.Health)
    } else {
        e.Attack(p.Health, e.Atk)

        fmt.Println(p.Health)
    }
}

func main() {
    //seed rand generator for the current run
    rand.Seed(time.Now().UTC().UnixNano())
    p := Character{20, 5}
    e := Character{20, 5}
    combatRound(p, e)
    fmt.Println("Player Health: %d \n Enemy Health: %d", p.Health, e.Health)

}
3
  • func combatRound(ref p, ref e Character) { what is this ref business? Does it even compile? Commented Feb 13, 2016 at 22:40
  • oh shit, that was something I was trying and forgot to change. sorry fixed. Commented Feb 13, 2016 at 22:44
  • 1
    You'd be better to name your interface Attacker then any Character that has an Attack function will satisfy it. I think you could even make a AttackTarget interface and then the Attack function would be target.TakeDamage(c.atk). Then Characters, Objects, Traps, Boxes, whatever, can Attack and TakeDamage individually. Commented Feb 14, 2016 at 1:29

1 Answer 1

2

In Go, the parameters and receivers of a call to a function or method are always passed by value (by assignment).

For example,

package main

import (
    "fmt"
    "math/rand"
    "time"
)

type Attacker interface {
    Attacks(a *Character)
}

type Character struct {
    Health, Attack int
}

func (c *Character) Attacks(a *Character) {
    a.Health -= c.Attack
}

func combatRound(player, enemy *Character) {
    if rand.Intn(100) <= 30 {
        player, enemy = enemy, player
    }
    player.Attacks(enemy)
}

func main() {
    rand.Seed(time.Now().UnixNano())
    p := &Character{20, 5}
    e := &Character{20, 5}
    combatRound(p, e)
    fmt.Printf("Player Health: %d\nEnemy Health: %d\n", p.Health, e.Health)
}

Output:

$ go run attack.go
Player Health: 20 
Enemy Health: 15
$ go run attack.go
Player Health: 20 
Enemy Health: 15
$ go run attack.go
Player Health: 15 
Enemy Health: 20

The Go Programming Language Specification

Assignments

Assignment = ExpressionList assign_op ExpressionList .

assign_op = [ add_op | mul_op ] "=" .

Each left-hand side operand must be addressable, a map index expression, or (for = assignments only) the blank identifier. Operands may be parenthesized.

A tuple assignment assigns the individual elements of a multi-valued operation to a list of variables. There are two forms. In the first, the right hand operand is a single multi-valued expression such as a function call, a channel or map operation, or a type assertion. The number of operands on the left hand side must match the number of values. For instance, if f is a function returning two values,

x, y = f()

assigns the first value to x and the second to y. In the second form, the number of operands on the left must equal the number of expressions on the right, each of which must be single-valued, and the nth expression on the right is assigned to the nth operand on the left:

one, two, three = '一', '二', '三'

The assignment proceeds in two phases. First, the operands of index expressions and pointer indirections (including implicit pointer indirections in selectors) on the left and the expressions on the right are all evaluated in the usual order. Second, the assignments are carried out in left-to-right order.

a, b = b, a  // exchange a and b

The Go statement

player, enemy = enemy, player

is the second form of a tuple assignment. It's the idiomatic way to swap or exchange two values. The operands on the left and the expressions on the right are evaluated before the assignments take place. The compiler takes care of any temporary variables for you.

In the combatRound function, for 31 out ot 100 (interval [0, 30] of [0, 100)) calls, on average, roles are reversed or swapped, the enemy (defender) repulses the player (attacker). Swapping the pointers to the Characters reflects the role reversal. and the player's health declines, not the enemy's.

Sign up to request clarification or add additional context in comments.

2 Comments

I see what you did, and it's so much more legible and straightforward. I see what's happening now, and was able to fix my code. Can you explain real quick what is happening with player, enemy = enemy, player? That's just reassigning the objects? without a temp variable? I'm not following, sorry. usually to swap you see something like var temp = enemy enemy = player player = temp it actually works this way in go? and where can i read more about what you are doing there?
@nathanrogers: For player, enemy = enemy, player, see my revised answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.