在函数内部更改指针参数的值。

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

Change value of pointered argument inside a function

问题

我在Go语言中遇到了一个看起来应该很简单的问题。

我写了一个小的Go Playground来更容易地解释我的问题 => https://play.golang.org/p/Sm0SzrvEZS_o

    package main

    import (
	    "github.com/sirupsen/logrus"
    )

    type toto struct {
    	name string
    }

    func transform (data ...interface{}) {
    	logrus.Info("data before ", data)
    	
    	data[0] = "tutu"
    	
    	logrus.Info("data after ", data)
    }

    func main() {
    	var titi toto
	
    	logrus.Info("titi before ", titi) // -> empty
	
    	transform(&titi)
	
    	logrus.Info("titi after ", titi) // -> should have a name but don't
    }

目标是将一个结构体传递给一个函数,在其中修改它,并在调用函数中继续使用它。不幸的是,参数在子函数中被修改,但没有传递到调用者中。

作为这门语言的初学者,也许我在某个地方错过了什么... 非常感谢您的帮助。

英文:

I'm stuck on something that seems/should be easy in Go.

I wrote a small go playground to explain my problem more easily => https://play.golang.org/p/Sm0SzrvEZS_o

    package main

    import (
	    "github.com/sirupsen/logrus"
    )

    type toto struct {
    	name string
    }

    func transform (data ...interface{}) {
    	logrus.Info("data before ", data)
    	
    	data[0] = "tutu"
    	
    	logrus.Info("data after ", data)
    }

    func main() {
    	var titi toto
	
    	logrus.Info("titi before ", titi) // -> empty
	
    	transform(&titi)
	
    	logrus.Info("titi after ", titi) // -> should have a name but don't
    }

The goal is to pass a struct to a function, modifying in it and continue to use it in the caller function. Sadly, the argument is modified inside the child function but don't move into the caller.

I'm a beginner in this language, maybe I just missed something somewhere... Many thanks in advance for your help

答案1

得分: 1

这似乎可以实现:

package main

type toto struct { name string }

func transform (data ...interface{}) {
   t := data[0].(*toto)
   t.name = "tutu"
}

func main() {
   var titi toto
   transform(&titi)
   println(titi.name == "tutu")
}
英文:

This seems to do it:

package main

type toto struct { name string }

func transform (data ...interface{}) {
   t := data[0].(*toto)
   t.name = "tutu"
}

func main() {
   var titi toto
   transform(&titi)
   println(titi.name == "tutu")
}

答案2

得分: 0

听起来你想要一个指针。

在你的示例中,你使用了一个interface{}的数组,有什么特殊的原因吗?一般来说,在Go语言中应该明确指定类型,特别是当你处理一个简单的结构体时。

package main

import (
	"log"
)

type toto struct {
	Name string
}

// 用于打印的辅助方法
func (t *toto) String() string {
	return t.Name
}

// transform函数接受一个指向toto结构体的指针数组
func transform(totos ...*toto) {
	log.Printf("totos before: %v", totos)

	// 不安全的数组访问!
	totos[0].Name = "tutu"

	log.Printf("totos after: %v", totos)
}

func main() {
	// 在Go语言中,变量通常是这样定义的
	titi := toto{}

	transform(&titi)
}
英文:

Sounds like you want a pointer.

In your example you use an array of interface{}, is there a particular reason for this? In general you should be explicit with your types in Go, especially since you're dealing with a simple struct.

package main

import (
	"log"
)

type toto struct {
	Name string
}

// to help with printing
func (t *toto) String() string {
	return t.Name
}

// transform takes an array of pointers to the toto struct
func transform(totos ...*toto) {
	log.Printf("totos before: %v", totos)

	// unsafe array access!
	totos[0].Name = "tutu"

	log.Printf("totos after: %v", totos)
}

func main() {
	// variables in Go are usually defined like this
	titi := toto{}

	transform(&titi)
}

答案3

得分: -1

在Go语言中,作为函数参数传递的变量实际上是变量的副本,而不是实际的变量本身。如果你想修改传递的变量,你需要将其作为指针传递。

个人而言,每当我创建一个接受结构体的函数时,我会将函数设置为接受该结构体实例的指针。这样做有以下好处:更节省内存(因为每次调用函数时,程序不需要创建变量的副本),并且允许我修改传递的结构体实例。

以下是我会这样做的方式:

package main

import (
	"github.com/sirupsen/logrus"
)

type toto struct {
	name string
}

func transform(t *toto) {
	logrus.Info("t before: ", t)
	
	// 由于t是指向toto结构体的指针,
	// 我可以使用“点”运算符将“tutu”直接赋值给“name”字段
	t.name = "tutu"
	
	logrus.Info("t after: ", t)
}

func main() {
	// 初始化一个指向toto实例的指针
	titi := &toto{}
	
	logrus.Info("titi before: ", titi) // -> 空
	
	// 这样做是因为transform()接受一个指向toto结构体的指针,
	// 而titi是一个指向toto实例的指针
	transform(titi)
	
	logrus.Info("titi after (as a pointer): ", titi) // -> 非空
	logrus.Info("titi after (as a value): ", *titi) // -> 也非空
}

希望对你有帮助!

英文:

In Go, the variable that's passed as a parameter in a function is actually a copy of the variable, not the actual variable itself. If you want to modify the variable that's passed, you need to pass it in as a pointer.

Personally, whenever I create a function that accepts a struct, I set the function to accept a pointer to an instance of that struct. This has the benefits of being more memory efficient (since my program doesn't have to create copies of the variable every time the function is called) and it allows me to modify the instance of the struct that I pass.

This is how I would do it:

package main

import (
	"github.com/sirupsen/logrus"
)

type toto struct {
	name string
}

func transform (t *toto) {
	logrus.Info("t before: ", t)
	
    // since t is a pointer to a toto struct, 
    // I can directly assign "tutu" to the "name" field 
    // using the "dot" operator 
	t.name = "tutu"
	
	logrus.Info("t after: ", t)
}

func main() {
    // init a pointer to a toto instance
	titi := &toto{}
	
	logrus.Info("titi before: ", titi) // -> empty
	
    // this works because transform() accepts a pointer
    // to a toto struct and and titi is a pointer to a toto instance
	transform(titi)
	
	logrus.Info("titi after (as a pointer): ", titi) // -> not empty
	logrus.Info("titi after (as a value): ", *titi) // -> also not empty
}

huangapple
  • 本文由 发表于 2021年5月27日 20:43:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/67722373.html
匿名

发表评论

匿名网友

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

确定