英文:
How can I type select an interface on a pointer-to-pointer in Go?
问题
我有一对定义如下的接口:
type Marshaler interface {
Marshal() ([]byte, error)
}
type Unmarshaler interface {
Unmarshal([]byte) error
}
我有一个简单的类型实现了这些接口:
type Foo struct{}
func (f *Foo) Marshal() ([]byte, error) {
return json.Marshal(f)
}
func (f *Foo) Unmarshal(data []byte) error {
return json.Unmarshal(data, &f)
}
我正在使用一个定义了不同接口的库,并像这样实现它:
func FromDb(target interface{}) { ... }
传递给target
的值是一个指向指针的指针:
fmt.Println("%T\n", target) // 打印 **main.Foo
通常,这个函数会进行类型切换,然后对底层类型进行操作。我想为所有实现了我的Unmarshaler
接口的类型编写通用代码,但是我无法弄清楚如何从特定类型的指向指针的指针转换到我的接口。
你不能在指向指针的指针上定义方法:
func (f **Foo) Unmarshal(data []byte) error {
return json.Unmarshal(data, f)
}
// 编译错误:无效的接收器类型 **Foo(*Foo 是一个无名类型)
你也不能在指针类型上定义接收器方法:
type FooPtr *Foo
func (f *FooPtr) Unmarshal(data []byte) error {
return json.Unmarshal(data, f)
}
// 编译错误:无效的接收器类型 FooPtr(FooPtr 是一个指针类型)
将其转换为Unmarshaler
类型也不起作用:
x := target.(Unmarshaler)
// 报错:接口转换:**main.Foo 不是 main.Unmarshaler:缺少方法 Unmarshal
将其转换为*Unmarshaler
也不起作用:
x := target.(*Unmarshaler)
// 报错:接口转换:接口是 **main.Foo,而不是 *main.Unmarshaler
如何在不需要针对每个可能的实现类型进行切换的情况下,从指向指针的指针类型转换为我的接口类型?
英文:
I have a pair of interfaces defined like so:
type Marshaler interface {
Marshal() ([]byte, error)
}
type Unmarshaler interface {
Unmarshal([]byte) error
}
I have a simple type which implement these:
type Foo struct{}
func (f *Foo) Marshal() ([]byte, error) {
return json.Marshal(f)
}
func (f *Foo) Unmarshal(data []byte) error {
return json.Unmarshal(data, &f)
}
I am using a library which defines a different interface, and implementing it like so:
func FromDb(target interface{}) { ... }
The value being passed for target
is a pointer to pointer:
fmt.Println("%T\n", target) // Prints **main.Foo
Typically this function does a type switch and then operates on the type underneath. I would like to have common code for all types that implement my Unmarshaler
interface but can't figure out how to get from a pointer-to-pointer of a specific type to my interface.
You cannot define methods on a pointer to a pointer:
func (f **Foo) Unmarshal(data []byte) error {
return json.Unmarshal(data, f)
}
// compile error: invalid receiver type **Foo (*Foo is an unnamed type)
You cannot define receiver methods on pointer types:
type FooPtr *Foo
func (f *FooPtr) Unmarshal(data []byte) error {
return json.Unmarshal(data, f)
}
// compile error: invalid receiver type FooPtr (FooPtr is a pointer type)
Casting to Unmarshaler
doesn't work:
x := target.(Unmarshaler)
// panic: interface conversion: **main.Foo is not main.Unmarshaler: missing method Unmarshal
Casting to *Unmarshaler
doesn't work either:
x := target.(*Unmarshaler)
// panic: interface conversion: interface is **main.Foo, not *main.Unmarshaler
How can I get from this pointer-to-pointer type to my interface type without needing to switch on every possible implementor type?
答案1
得分: 3
这是一个示例代码,它展示了如何使用指向指针的语义等效的接收器。代码如下:
package main
import "fmt"
type P *int
type W struct{ p P }
func (w *W) foo() {
fmt.Println(*w.p)
}
func main() {
var p P = new(int)
*p = 42
w := W{p}
w.foo()
}
输出结果为:
42
需要注意的是,上述代码中的 fmt.Println(*w.p)
实际上等同于 fmt.Println(*(*w).p)
,编译器会自动为你完成这个额外的工作。
英文:
It's ugly, but is is possible to have the semantic equivalent of a pointer to pointer receiver. For example:
package main
import "fmt"
type P *int
type W struct{ p P }
func (w *W) foo() {
fmt.Println(*w.p)
}
func main() {
var p P = new(int)
*p = 42
w := W{p}
w.foo()
}
Output:
42
Note that
fmt.Println(*w.p)
above is actually
fmt.Println(*(*w).p)
where the extra work is done for you by the compiler automagically.
答案2
得分: 2
如果target
是一个**Foo
,而*Foo
实现了Unmarshaler
接口,你可以这样做:
var x Unmarshaler = *target
如果target
是一个包含**Foo
的interface{}
,则可以使用以下方式:
var x Unmarshaler = *(target.(**Foo))
如果你使用类型切换,也是类似的思路。
每当我需要处理指向指针或引用的情况时,变量的生命周期通常很短,它们很快就会回到单个指针(或普通引用)的状态。
我会评估指向指针的确实是否在当前的使用场景中是必需的,或者是否可以做一些类似的操作。
英文:
If target
is a **Foo
and *Foo
implements Unmarshaler
, you can do:
var x Unmarshaler = *target
If target is a an interface{}
containing a **Foo
, this would work instead:
var x Unmarshaler = *(target.(**Foo))
It's a similar idea if you have a type switch.
Whenever I have to deal with pointer-to-pointer or pointer-to-reference, the variable life-time is generally pretty short and they quickly go back to being a single pointer (or plain reference) again.
I'd evaluate whether the pointer-to-pointer is indeed required for the use case at hand or whether you can do something like that.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论