如何将结构体作为参数传递给函数?

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

How can I pass a struct to a function as parameter?

问题

如何在golang中将结构体作为参数传递给函数?这是我的代码:

package main

import (
	"fmt"
)

type MyClass struct {
	Name string
}

func test(class interface{}) {
	fmt.Println(class.(MyClass).Name)
}

func main() {

	test(MyClass{Name: "Jhon"})
}

当我运行它时,我得到了以下错误:

# command-line-arguments
/tmp/sandbox290239038/main.go:12: class.Name undefined (type interface {} has no field or method Name)

这是play.golang.org的链接:fiddle

英文:

How can I pass a struct to function as a parameter in golang? There is my code:

package main

import (
	"fmt"
)

type MyClass struct {
	Name string
}

func test(class interface{}) {
	fmt.Println(class.Name)
}

func main() {

	test(MyClass{Name: "Jhon"})
}

when I run it, I am getting an error like this

# command-line-arguments
/tmp/sandbox290239038/main.go:12: class.Name undefined (type interface {} has no field or method Name)

there is play.golang.org fiddle address.

答案1

得分: 48

你正在寻找的是:

func test(class MyClass) {
    fmt.Println(class.Name)
}

目前这个方法将class识别为实现了空接口的某个对象(这意味着在该作用域中,它的字段和方法是完全未知的),这就是为什么你会得到错误。

你的另一个选择是这样的:

func test(class interface{}) {
    if c, ok := class.(MyClass); ok { // 对其进行类型断言
        fmt.Println(c.Name)
    }
}

但在你的示例中没有必要这样做。只有在你要进行类型切换或者根据class的实际类型执行不同的代码路径时才有意义。

英文:

You're looking for;

func test(class MyClass) {
    fmt.Println(class.Name)
}

As it stands the method recognizes class as some object which implements the empty interface (meaning in that scope it's fields and methods are completely unknown) which is why you get the error.

Your other option is something like this;

func test(class interface{}) {
     if c, ok := class.(MyClass); ok { // type assert on it    
         fmt.Println(c.Name)
     }
}

But there is no reason to in your example. It only makes sense if you're going to do a type switch or have multiple code paths that do different things based on the actual type of class.

答案2

得分: 20

根据您的需求,您至少有两个选项:

  1. 在结构类型上定义方法
  2. 接受结构类型作为参数的函数
package main

import "fmt"

type MyClass struct {
    Name string
}

func main() {
    cls := MyClass{Name: "Jhon"}

    // 以下两个调用产生相同的结果
    cls.StructMethod()  // "Jhon"
    FuncPassStruct(cls) // "Jhon"
}

// 在结构类型上定义的方法
func (class MyClass) StructMethod() {
    fmt.Println(class.Name)
}

// 接受结构类型作为参数的函数
func FuncPassStruct(class MyClass) {
    fmt.Println(class.Name)
}

我相信其他人可能会提供一些我忘记的接口技巧。

英文:

Depending on your needs, you have (at least) two options:

  1. Method on the struct type
  2. Func that takes struct type as parameter

<div></div>

package main

import &quot;fmt&quot;

type MyClass struct {
	Name string
}

func main() {
	cls := MyClass{Name: &quot;Jhon&quot;}

	// Both calls below produce same result
	cls.StructMethod()  // &quot;Jhon&quot;
	FuncPassStruct(cls) // &quot;Jhon&quot;
}

// Method on struct type
func (class MyClass) StructMethod() {
	fmt.Println(class.Name)
}

// Function that takes struct type as the parameter
func FuncPassStruct(class MyClass) {
	fmt.Println(class.Name)
}

I'm sure others may provide some interface wizardry I'm forgetting.

答案3

得分: 3

如果你真的想以通用的方式发送任何结构体,就像你在原始问题中所写的那样(使用空接口参数),以便可以访问AnyStruct.SomeField和AnotherStruct.SomeField,或者AnyOtherStruct.AnyField,我认为Go语言的反射功能是一个不错的选择。

例如,如果你看一下JSON marshal函数,它接受几乎任何结构体作为一个"v"参数传递给一个带有空接口参数的函数。然后,marshal函数最终调用:

e.reflectValue(reflect.ValueOf(v), opts)

但是你可能正在寻找其他答案中提到的一些简单的方法,这些方法不需要高级反射(一种通用的编程方式)。

然而,我发布这个答案是为了其他读者有兴趣在不需要事先知道结构体字段的情况下通用地发送结构体。

JSON解析器需要通用地访问结构体的原因是为了方便用户定义任何他想要的结构体,然后Go语言会自动识别结构体并将其映射到JSON语法。你可以想象有100多种不同的结构体布局,你只想将它们放入一个文本文件中,而不需要事先知道所有结构体的布局-该函数可以在运行时确定,这就是反射的工作原理(其他语言称之为运行时类型信息、元编程等)。

英文:

If you really want to send any struct in generically like it is written in your original question (an empty interface parameter) so that AnyStruct.SomeField and AnotherStruct.SomeField, or AnyOtherStruct.AnyField can be accessed, AFAIK the reflecton features of go are the way to go.

For example if you look at the JSON marshal function it accepts pretty much any struct as a ("v") parameter sent in to a function with an empty interface parameter. Then that marshal function ends up calling

e.reflectValue(reflect.ValueOf(v), opts)

But you are probably looking for something simple as the other answers have suggested, which would not need advanced reflection (a sort of generic way of programming)

However I post this answer in case other readers are interested in sending structs in generally without needing to know up front what the struct fields are.

The reason a JSON parser needs to generically access a struct is for convenience of the user defining any struct he wants, and then Go automagically figures out the struct and maps it to a JSON syntax. You could imagine 100's of different struct layouts that you just want to place into a text file, without knowing all your struct layouts upfront - the function can figure out it at run time, which is how reflection works (other languages call it run time type information, meta programming, and similar).

答案4

得分: 1

请查看DebugReceive方法。它使用了名为user的结构体,以及它的方法。链接:https://play.golang.org/p/E_WkLWGdeB

package main

import "fmt"

// user定义了程序中的用户。
type user struct {
	name   string
	email  string
	status string
}

func debug(u user) {
	fmt.Printf("%+v\n", u)
}

// notify实现了一个带有值接收器的方法。
func (u user) notify() {
	fmt.Printf("User: 发送邮件给 %s<%s>\n", u.name, u.email)
}

// changeEmail实现了一个带有指针接收器的方法。
func (u *user) changeEmail(email string) {
	u.email = email
}

func (u *user) changeName(name string) {
	u.name = name
}

func (u *user) Send() {
	u.notify()
}

// main是应用程序的入口点。
func main() {
	// 类型为user的指针也可以用于使用值接收器声明的方法。
	john := &user{"John", "john@exemple.com", "enabled"}

	john.changeName("John Smith")
	john.changeEmail("john@gmail.com")
	john.notify()

	Receive(john)
	debug(user{"Willy", "Willy@exemple.com", "enabled"})
}

func Receive(user interface {
	changeName(s string)
	changeEmail(s string)
	Send()
}) {
	user.changeName("Bill")
	user.changeEmail("bill@billy-exemple.com")
	user.Send()
}


英文:

Please take a look over the Debug ,Receive methods. It uses stuct user, with its methods. https://play.golang.org/p/E_WkLWGdeB

package main

import &quot;fmt&quot;

// user defines a user in the program.
type user struct {
	name   string
	email  string
	status string
}

func debug(u user) {
	fmt.Printf(&quot;%+v\n&quot;, u)
}

// notify implements a method with a value receiver.
func (u user) notify() {
	fmt.Printf(&quot;User: Sending User Email To %s&lt;%s&gt;\n&quot;, u.name, u.email)
}

// changeEmail implements a method with a pointer receiver.
func (u *user) changeEmail(email string) {
	u.email = email
}

func (u *user) changeName(name string) {
	u.name = name
}

func (u *user) Send() {
	u.notify()
}

// main is the entry point for the application.
func main() {
	// Pointers of type user can also be used to methods
	// declared with a value receiver.
	john := &amp;user{&quot;John&quot;, &quot;john@exemple.com&quot;, &quot;enabled&quot;}

	john.changeName(&quot;John Smith&quot;)
	john.changeEmail(&quot;john@gmail.com&quot;)
	john.notify()

	Receive(john)
	debug(user{&quot;Willy&quot;, &quot;Willy@exemple.com&quot;, &quot;enabled&quot;})
}

func Receive(user interface {
	changeName(s string)
	changeEmail(s string)
	Send()
}) {
	user.changeName(&quot;Bill&quot;)
	user.changeEmail(&quot;bill@billy-exemple.com&quot;)
	user.Send()
}


答案5

得分: 0

你需要使用.()语法将参数从接口转换为特定的结构体类型。

package main

import (
	"fmt"
)

type MyClass struct {
	Name string
}

func test(class interface{}) {
	classStr := class.(MyClass)
	fmt.Println(classStr.Name)
}

func main() {

	test(MyClass{Name: "Jhon"})
}
英文:

You need to cast the parameter from an interface to the specific struct by using the .() syntax

package main

import (
	&quot;fmt&quot;
)

type MyClass struct {
	Name string
}

func test(class interface{}) {
	classStr := class.(MyClass)
	fmt.Println(classStr.Name)
}

func main() {

	test(MyClass{Name: &quot;Jhon&quot;})
}

huangapple
  • 本文由 发表于 2015年4月23日 02:04:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/29805583.html
匿名

发表评论

匿名网友

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

确定