在Go语言中,访问和更新结构体中的项有一种惯用的方式。

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

Idiomatic golang: accessing and updating an item in a struct

问题

所以我正在尝试编写一些代码,使我能够编辑结构体中数组中的值。这个示例使用"Status"作为可能要更改的值,但这只是为了简化以便更好地表达我的意图。

package main

import (
	"fmt"
)

type Parent struct {
	Children []Child
}

type Child struct {
	Status string
}

func (p *Parent) Add() *Child {
	var child Child
	child.Status = "1"
	p.Children = append(p.Children, child)
	return &p.Children[len(p.Children)-1]
}

func main() {
	var p Parent
	child := p.Add()
	child.Status = "2"
	fmt.Println(p)
	fmt.Println(child)
}

这种方式感觉不太"正规"。在golang中应该如何处理这种情况?当然,我可以将值作为参数传递进去,但在我的特定情况下,我想在添加子项后编辑Child结构体内部的函数指针(为了保持代码简洁,此处未包含)。这样做感觉更好,但也许我只需要将它们作为参数传递给Add方法?

例如:

func (p *Parent) Add(fn1 func(), fn2 func()) *Child {
	// 在这里处理函数指针
}

无论如何,我只是想知道是否有人对这种情况有什么想法。

英文:

So I am trying to write some code that allows me to edit values in an array in a struct. This example uses "Status" as a possible value to alter, but this is just a simplification to try to get my intent across.

package main

import(
  "fmt"
)

type Parent struct {
  Children []Child
}

type Child struct {
  Status string
}

func (p *Parent) Add() *Child {
  var child Child
  child.Status = "1"
  p.Children = append(p.Children, child)
  return &p.Children[len(p.Children)-1]
}

func main() {
  var p Parent
  child := p.Add()
  child.Status = "2"
  fmt.Println(p)
  fmt.Println(child)
}

This doesn't feel "proper". How should I do this in golang? Certainly I could pass the value in as a parameter, but in my particular case I would like to edit function pointers that are inside the Child struct (not in this code to keep it short) after having added the child. That feels nicer, but maybe I just need to pass them as parameters to the Add method?

eg

func (p *Parent) Add(fn1 func(), fn2 func()) *Child {

Anyway just wondering if anybody has any thoughts on this type of situation.

答案1

得分: 2

我认为你应该在Add方法之外创建Child并将其传递进去。如果你想要操作Child,请在传递之前进行操作。你可以使用Child结构体上的方法来实现:

func (c *Child) Init(fn1 func(), fn2 func()) {
  c.Status = "1"
  ...
}

func (p *Parent) Add(c *Child) *Child {
  p.Children = append(p.Children, c)
  return c
}

func main() {
  var p Parent
  var child Child
  child.Init(...)       // <- 在这里传递一些内容...
  p.Add(&child)
  child.Status = "2"
  fmt.Println(p)
  fmt.Println(child)
}
英文:

I think you should create the Child outside of the Add method and pass it in. If you want to manipulate the Child, do that before you passed it in. You might use methods on the Child struct to do that:

func (c *Child) Init(fn1 func(), fn2 func()) {
  c.Status = &quot;1&quot;
  ...
}

func (p *Parent) Add(c *Child) *Child {
  p.Children = append(p.Children, c)
  return c
}

func main() {
  var p Parent
  var child Child
  child.Init(...)       // &lt;- pass something in there...
  p.Add(&amp;child)
  child.Status = &quot;2&quot;
  fmt.Println(p)
  fmt.Println(child)
}

答案2

得分: 1

我建议以最简单的方式完成这个任务。记住KISS原则,即“保持简单”。系统的每个部分只做一件事

按照这个逻辑,你的Add(c *Child)方法应该只负责添加一个子元素。创建Child应该单独完成,同样,给Child设置一些独特的属性也应该单独完成。

对于你的OpenGL菜单系统,这种方法也很适用:

m := NewMenu()
t := NewText(text)
t.OnClick = someCallback
// 其他t的初始化操作。
m.Add(t)
// 如果t是一个指针并且m.Add没有进行复制,那么稍后你仍然可以更改t。
t.OnHover = someOtherCallback

关于是否将标签公开,或者隐藏它们并提供getter和setter方法,这取决于你的系统设计和一致性要求,由你自己决定。

英文:

I'd suggest doing this in the simplest way possible. Remember the KISS principle. One part of the system does one and only one thing.

Following this logic, your Add(c *Child) method should only add a child. Creating a Child should be done separately, same for giving a Child some unique properties.

For your OpenGL menu system, this approach fits nicely as well:

m := NewMenu()
t := NewText(text)
t.OnClick = someCallback
// Some other t initialisation.
m.Add(t)
// Some time later you can still change t if it&#39;s a pointer and m.Add
// doesn&#39;t copy.
t.OnHover = someOtherCallback

The decision on whether to keep your labels exported, or hide them and provide getters/setters is up to you, and depends solely on your system's design and consistency requirements.

答案3

得分: 1

好的,以下是翻译好的代码:

package main

import (
	"fmt"
)

type HairColor func() string
type Parent struct {
	Children []*Child
}

type Child struct {
	Age           int
	ShowHairColor HairColor
}

func (p *Parent) Add(c *Child) {
	p.Children = append(p.Children, c)
}

func main() {
	var parent Parent
	var child Child

	child.Age = 10
	parent.Add(&child)

	child.ShowHairColor = func() string {
		return "red"
	}
	fmt.Printf("%v\n", parent.Children[0])
	fmt.Printf("%v\n", child)

	fmt.Println(parent.Children[0].ShowHairColor())
}

这段代码主要涉及指针的正确使用。Parent 结构体包含一个 Children 切片,Child 结构体包含一个 Age 字段和一个 ShowHairColor 函数类型的字段。Parent 结构体有一个 Add 方法,用于向 Children 切片中添加子元素。在 main 函数中,创建了一个 parent 变量和一个 child 变量。然后,将 child 的地址传递给 parent.Add 方法,将其添加到 parent.Children 切片中。接着,为 childShowHairColor 字段赋值一个返回字符串 "red" 的匿名函数。最后,打印输出了 parent.Children[0]child 的值,并调用了 parent.Children[0].ShowHairColor() 方法并打印输出结果。

英文:

Ok the following works for me. The code is changed again to try to focus more clearly on the particular issue I was having. It all comes down to properly using pointers. Thanks for the suggestions.

package main

import (
	&quot;fmt&quot;
)

type HairColor func() string
type Parent struct {
	Children []*Child
}

type Child struct {
	Age           int
	ShowHairColor HairColor
}

func (p *Parent) Add(c *Child) {
	p.Children = append(p.Children, c)
}

func main() {
	var parent Parent
	var child Child

	child.Age = 10
	parent.Add(&amp;child)

	child.ShowHairColor = func() string {
		return &quot;red&quot;
	}
	fmt.Printf(&quot;%v\n&quot;, parent.Children[0])
	fmt.Printf(&quot;%v\n&quot;, child)

	fmt.Println(parent.Children[0].ShowHairColor())
}

huangapple
  • 本文由 发表于 2014年11月13日 20:57:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/26909443.html
匿名

发表评论

匿名网友

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

确定