当前位置: 首页 > 面试题库 >

解组接口类型

郜联
2023-03-14
问题内容

我有一些代码已经被转储并实际上被卡住了-之前我已经使用过RPC和JSON方面的东西,但是当它在本地运行良好时,我似乎无法使其在RPC上正常工作。

package main

import (
    "log"
    "net"
    "net/rpc"
    "net/rpc/jsonrpc"
    "reflect"
)

type Foo interface {
    SayHello() error
}

type fakeFoo struct {
    internalValue string
}

func NewFakeFoo() *fakeFoo {
    f := &fakeFoo{}
    f.internalValue = "123456789012347"
    return f
}

func (m *fakeFoo) SayHello() error {
    return nil
}

type FooManager struct {
    availableFoos []Foo
}

func NewFooManager() *FooManager {
    p := new(FooManager)
    p.availableFoos = make([]Foo, 0)
    return p
}

func AddFoo(mm *FooManager, m Foo) {
    mm.availableFoos = append(mm.availableFoos, m)
    log.Println("Added type ", reflect.TypeOf(m))
}

func (mm *FooManager) GetAvailableFoos(in []Foo, out *[]Foo) error {

    log.Println("availableFoos:", reflect.TypeOf(mm.availableFoos))
    log.Println("*out is", reflect.TypeOf(*out))

    *out = append(in, mm.availableFoos...)

    log.Println("Out is:", reflect.TypeOf(*out))

    return nil
}

func startServer(mm *FooManager) {
    server := rpc.NewServer()
    server.Register(mm)

    l, e := net.Listen("tcp", ":8222")
    if e != nil {
        log.Fatal("listen error:", e)
    }

    for {
        conn, err := l.Accept()
        log.Println("Incoming!")
        if err != nil {
            log.Fatal(err)
        }

        go server.ServeCodec(jsonrpc.NewServerCodec(conn))
    }
}

func main() {
    fake1 := NewFakeFoo()

    fooHolder := NewFooManager()
    AddFoo(fooHolder, fake1)
    go startServer(fooHolder)

    log.Println("Using standard function call")
    var foos []Foo
    fooHolder.GetAvailableFoos(foos, &foos)
    log.Println(foos)

    log.Println("Using RPC call")
    conn, err := net.Dial("tcp", "localhost:8222")
    if err != nil {
        log.Fatalln(err)
    }
    defer conn.Close()
    c := jsonrpc.NewClient(conn)

    err = c.Call("FooManager.GetAvailableFoos", foos, &foos)
    if err != nil {
        log.Println(foos)
        log.Fatal("GetAvailableFoos error:", err)
    }
    log.Println("Success: ", foos)
}

(也在这里,但没有可用的TCP!http:
//play.golang.org/p/HmK-K09D2J )

输出令人惊讶,因为它表明编组而不是实际数据出了点问题-
在Wireshark中运行它,我可以看到数据以正确的格式发送(我在另一个问题中使用类似的技术也取得了成功),但是可以为了我的一生,不要让它停止抛出编组错误。

运行此命令的输出如下:

2015/09/07 10:04:35 Added type  *main.fakeFoo
2015/09/07 10:04:35 Using standard function call
2015/09/07 10:04:35 availableFoos: []main.Foo
2015/09/07 10:04:35 *out is []main.Foo
2015/09/07 10:04:35 Out is: []main.Foo
2015/09/07 10:04:35 [0x1870a540]
2015/09/07 10:04:35 Using RPC call
2015/09/07 10:04:35 Incoming!
2015/09/07 10:04:35 [0x1870a540]
2015/09/07 10:04:35 GetAvailableFoos error:json: cannot unmarshal object into Go value of type main.Foo
exit status 1

我是否错过了接口/类型技巧,或者这是Go编组中的错误?


问题答案:

所有封送/拆封都有此问题。

您可以从接口类型变量中进行编组,因为对象在本地存在,因此反射器知道基础类型。

您无法解组接口类型,因为反射器不知道为新实例提供哪种具体类型来接收封送处理的数据。

在某些编组/非编组框架中,我们需要其他信息来帮助反射器。例如,在Java
Json(jackson)中,我们使用JsonTypeInfo批注指定类类型,请参考this。

对于golang,您可以自己为自己的类型实现Unmarshaler接口。

// RawString is a raw encoded JSON object.
// It implements Marshaler and Unmarshaler and can
// be used to delay JSON decoding or precompute a JSON encoding.
type RawString string

// MarshalJSON returns *m as the JSON encoding of m.
func (m *RawString) MarshalJSON() ([]byte, error) {
    return []byte(*m), nil
}

// UnmarshalJSON sets *m to a copy of data.
func (m *RawString) UnmarshalJSON(data []byte) error {
    if m == nil {
        return errors.New("RawString: UnmarshalJSON on nil pointer")
    }
    *m += RawString(data)
    return nil
}

const data = `{"i":3, "S":{"phone": {"sales": "2223334444"}}}`

type A struct {
    I int64
    S RawString `sql:"type:json"`
}

func main() {
    a := A{}
    err := json.Unmarshal([]byte(data), &a)
    if err != nil {
        log.Fatal("Unmarshal failed", err)
    }
    fmt.Println("Done", a)
}


 类似资料:
  • 问题内容: 我想组成另一种类型的类型,但用假冒替换字段之一(这是接口值)。我遇到的问题是正在使用基础字段,因此我似乎无法覆盖该字段。 我在这里演示了这个问题:https : //play.golang.org/p/lHGnyjzIS-Y 为什么打印?我要打印。 谢谢。 问题答案: 通过,您正在调用 提升的 方法,方法接收者将是哪种类型,并调用何处是哪种类型,这就是它打印的原因。 在Go中有嵌入,但

  • 我现在正在关注与JAXB编组/解组相关的线程一段时间。 当我尝试将Java对象转换为XML时,我遇到了问题,其中有一些接口。后来我发现这可以使用EclipseLink的MOxy来解决。@Bdoughan在这里的文章 http://blog.bdoughan.com/2012/07/jaxb-no-annotations-required.html,答案非常有帮助。但是现在,当我试图将生成的相同XM

  • 问题内容: 当使用as函数参数类型,给定非指针类型并与之一起使用时,我在Go中遇到了一个错误。 因为一段代码值得一千个单词,所以下面是一个示例: 哪个输出: 把我的结构变成一个… 稍后再读一些内容,可以解释其中的一部分,它本身就是一种类型,而不是某种无类型的容器,它解释了,以及无法获取初始类型并返回。的事实。 从文档: 要将JSON解组为接口值,Unmarshal将其中之一存储在接口值中:[…]

  • 问题内容: 我通过Rabbitmq消息系统获得了。在发送之前, 我使用,将结果转换为并通过Rabbitmq发送。 我转换和发送的结构可以是:(更改了结构的名称和大小,但这没有关系) 要么 消息完全像a一样经过,并打印在另一面(某些服务器) 到目前为止,一切正常。现在,我试图将它们转换回它们的结构并声明类型。 第一次尝试是通过: 这是行不通的。当在拆封后打印它的类型时,我得到(?!?) 甚至比这更奇

  • 7.2. 接口类型 接口类型具体描述了一系列方法的集合,一个实现了这些方法的具体类型是这个接口类型的实例。 io.Writer类型是用的最广泛的接口之一,因为它提供了所有的类型写入bytes的抽象,包括文件类型,内存缓冲区,网络链接,HTTP客户端,压缩工具,哈希等等。io包中定义了很多其它有用的接口类型。Reader可以代表任意可以读取bytes的类型,Closer可以是任意可以关闭的值,例如一

  • 有一个短视频接口,我想知道如何能通过axios请求或者后端请求,直接获得视频地址 http://v.nrzj.vip/video.php?_t=0.9640358809997094 (1)放在浏览器可以直接下载视频,并每次下载不同的视频 (2)放在video的src中可以直接播放,并且每次创建video组件都会播放新的视频 (3)因为有时候接口会失败,失败时想做处理,所以src需要动态的,最好可以