修改结构体属性值

huangapple go评论74阅读模式
英文:

Go change struct property values

问题

尝试理解Go语言,还是相当新手。我知道C语言中的引用和指针,但在Go中似乎无法正常工作。我已经阅读了一些关于这个问题的文章,但仍然无法真正理解和实现解决方案。

角色具有生命值和攻击力。

角色可以进行攻击。

战斗回合调用Attack()函数,决定哪个角色在这一回合中进行攻击。

当Attack()函数被调用时,另一个角色的生命值会发生变化。

目前,角色的生命值从未改变过。

有人能给我一个简明的例子,展示如何正确地改变对象的值吗?

package main

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

// Character表示角色的生命值和攻击力
type Character struct {
	Health, Atk int
}

// Attack允许角色进行攻击
func (c *Character) Attack(health, atk int) {
	health -= atk
}

// CharacterInterface定义了角色的方法
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() {
	// 为当前运行种子生成随机数
	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)
}
英文:

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)

}

答案1

得分: 2

在Go语言中,对函数或方法的调用的参数和接收者总是通过值传递(通过赋值)。

例如,

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)
}

输出:

$ 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

> Go语言规范
>
> 赋值语句
>
> Assignment = ExpressionList assign_op ExpressionList .
>
> assign_op = [ add_op | mul_op ] "=" .
>
> 每个左操作数必须是可寻址的、映射索引表达式或(仅对于=赋值)空白标识符。操作数可以用括号括起来。
>
> 元组赋值将多值操作的各个元素分配给变量列表。有两种形式。在第一种形式中,右操作数是一个单个的多值表达式,例如函数调用、通道或映射操作或类型断言。左手边的操作数的数量必须与值的数量相匹配。例如,如果f是一个返回两个值的函数,
>
> x, y = f()
>
> 将第一个值分配给x,第二个值分配给y。在第二种形式中,左边的操作数的数量必须等于右边表达式的数量,每个表达式必须是单值的,第n个表达式在左边的第n个操作数上赋值:
>
> one, two, three = '一', '二', '三'
>
> 赋值分为两个阶段。首先,按照通常的顺序计算左边的索引表达式和指针间接引用(包括选择器中的隐式指针间接引用)的操作数以及右边的表达式。其次,按照从左到右的顺序执行赋值。
>
> a, b = b, a // 交换a和b

Go语句

player, enemy = enemy, player

是元组赋值的第二种形式。这是交换或交换两个值的惯用方式。在赋值发生之前,左边的操作数和右边的表达式都会被求值。编译器会为你处理任何临时变量。

combatRound函数中,对于100次调用中的31次(区间[0, 30]在[0, 100)之间),平均而言,角色会发生反转或交换,enemy(防御者)击退player(攻击者)。交换Characters的指针反映了角色的反转,玩家的生命值下降,而不是敌人的。

英文:

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 (
	&quot;fmt&quot;
	&quot;math/rand&quot;
	&quot;time&quot;
)

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) &lt;= 30 {
		player, enemy = enemy, player
	}
	player.Attacks(enemy)
}

func main() {
	rand.Seed(time.Now().UnixNano())
	p := &amp;Character{20, 5}
	e := &amp;Character{20, 5}
	combatRound(p, e)
	fmt.Printf(&quot;Player Health: %d\nEnemy Health: %d\n&quot;, 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.

huangapple
  • 本文由 发表于 2016年2月14日 06:34:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/35386151.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定