3

我有一对这样定义的接口:

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) // Prints **main.Foo

通常,此函数会进行类型切换,然后对下面的类型进行操作。我想为实现我的Unmarshaler接口的所有类型提供通用代码,但不知道如何从特定类型的指针到我的接口。

您不能在指向指针的指针上定义方法:

func (f **Foo) Unmarshal(data []byte) error {
    return json.Unmarshal(data, f)
}
// compile error: invalid receiver type **Foo (*Foo is an unnamed type)

您不能在指针类型上定义接收器方法:

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)

投射到Unmarshaler不起作用:

x := target.(Unmarshaler)
// panic: interface conversion: **main.Foo is not main.Unmarshaler: missing method Unmarshal

投射到*Unmarshaler也不起作用:

x := target.(*Unmarshaler)
// panic: interface conversion: interface is **main.Foo, not *main.Unmarshaler

我怎样才能从这个指针到指针类型到我的接口类型而不需要打开每个可能的实现类型?

4

2 回答 2

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)

编译器会自动为您完成额外的工作。

于 2013-09-04T16:26:33.490 回答
2

如果target是 a**Foo*Fooimplements Unmarshaler,你可以这样做:

var x Unmarshaler = *target

如果 target 是interface{}包含 a 的 a **Foo,则可以改为:

var x Unmarshaler = *(target.(**Foo))

如果你有一个类型开关,这是一个类似的想法。

每当我必须处理指向指针或指向引用的指针时,变量的生命周期通常很短,并且它们很快又回到单个指针(或普通引用)。

我会评估手头的用例是否确实需要指针指向指针,或者您是否可以做类似的事情。

于 2013-09-04T17:15:03.560 回答