How to force passing parameter as a pointer in Go?

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

How to force passing parameter as a pointer in Go?

问题

我正在实现一个在Go中使用JSON的应用层网络协议。

func ReadMessage(conn net.Conn, returnMessage interface{}) bool {
    messageBytes := // 从conn中读取

    error := json.Unmarshal(messageBytes, &returnMessage)
    if error != nil {
        return false
    }

    return true
}

该函数的第二个参数是一个结构体,用于解析消息。可以像这样调用该函数:

msg := MessageType1{}
ok := ReadMessage(conn, &msg)

或者不使用取地址符号(&):

msg := MessageType1{}
ok := ReadMessage(conn, msg)

尽管第二种方式可以编译通过,但它不会按预期工作,因为结构体是以副本的形式传递的,而不是作为引用传递,原始的msg将保持为空。因此,我想强制通过引用传递结构体,并在编译时捕获此错误。

将参数类型更改为*interface{}将无法编译通过:

cannot use &msg (type *MessageType1) as type *interface {} in function argument:
*interface {} is pointer to interface, not interface

是否有一种Go风格的正确实现方式?

英文:

I am implementing an application layer network protocol which uses JSON in Go.

func ReadMessage(conn net.Conn, returnMessage interface{}) bool {
	messageBytes := // read from conn

	error := json.Unmarshal(messageBytes, &returnMessage)
	if error != nil {
		return false
	}

	return true
}

The function takes a struct as its second parameter where the message is unmarshalled. The function can be called like this:

msg := MessageType1{}
ok := ReadMessage(conn, &msg)

Or without the ampersand (&)

msg := MessageType1{}
ok := ReadMessage(conn, msg)

which will compile, but not do what is should as the struct is passed as a copy, not as a reference and the original msg will remain empty. So I'd like to force passing the struct by reference and catch this error at compile time.

Changing the parameter type to *interface{} will not compile:

cannot use &msg (type *MessageType1) as type *interface {} in function argument:
*interface {} is pointer to interface, not interface

Is there some Go style way of doing this correctly?

答案1

得分: 4

在函数声明中没有一种方法可以做到这一点。

不过你可以使用反射,并在运行时当参数不是指针时引发 panic。

然而,也许你应该考虑改变你的代码设计。参数的具体类型不应该重要,它只需要实现你需要的接口或者不实现。

演示:http://play.golang.org/p/7Dw0EkFzbx

英文:

There is not a way to do this in the function declaration.

You can use reflection though and panic at runtime when the argument is not a pointer.

However maybe you should consider changing the design of your code. The concrete type of the argument should not matter. It either implements the interface you need or not.

Demo: http://play.golang.org/p/7Dw0EkFzbx

答案2

得分: 2

自Go 1.18版本开始,您可以使用泛型来实现这个功能:

func test[T any](dst *T) {
  //对dst进行操作
}
英文:

Since Go 1.18 you can do this using generics:

func test[T any](dst *T) {
  //Do something with dst
}

答案3

得分: 0

你可以将这个问题翻译为中文:

你无法强制要求*T始终具有T的方法集。因此,两者都实现了接口。
根据规范

任何其他类型T的方法集由具有接收器类型T的所有方法组成。相应指针类型T的方法集是具有接收器类型T或T的所有方法的集合(也就是说,它还包含T的方法集)。

相反,你可以使用语言的多返回值能力在函数中返回多个值,就像Volker已经提到的那样:

func ReadMessage(conn net.Conn) (interface{}, bool) {
    var returnMessage interface{}
    messageBytes := // 从conn中读取

    error := json.Unmarshal(messageBytes, &returnMessage)
    if error != nil {
        return nil, false
    }

    return returnMessage, true
}

你还应该考虑不返回类型interface{},而是返回一些有意义的类型。

英文:

You can't enforce this as *T always has the method set of T. Thus both implement the interface.
From the spec:

> The method set of any other type T consists of all methods with receiver type T. The method set of the corresponding pointer type *T is the set of all methods with receiver *T or T (that is, it also contains the method set of T).

What you can do instead is to use the language's ability to return multiple values in your function, as Volker already stated:

func ReadMessage(conn net.Conn) (interface{}, bool) {
    var returnMessage interface{}
    messageBytes := // read from conn

    error := json.Unmarshal(messageBytes, &returnMessage)
    if error != nil {
        return nil, false
    }

    return returnMessage, true
}

You should also consider not returning type interface{} but some meaningful type.

huangapple
  • 本文由 发表于 2014年3月3日 21:49:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/22148511.html
匿名

发表评论

匿名网友

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

确定