Golang/neoism:调用查询返回的对象的方法会导致恐慌。

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

Golang/neoism: calling methods of objects returned by query leads to panic

问题

尝试调用neoism.CypherQuery返回的Node对象的方法时,我一直收到"invalid memory address or nil pointer dereference"的错误。查询返回了一些结果(可以访问Node的Data属性),但调用任何方法都会导致错误。这些方法的接收者是*Node,而不是Node,但据我所知,这应该仍然有效。无论如何,我已经尝试获取对象的指针并在其上调用方法,但也没有成功。我真的被困住了...

以下是重现问题的示例代码(需要neoism和go-uuid包以及在本地主机上运行的Neo4J数据库):

package main

import (
	"code.google.com/p/go-uuid/uuid"
	"fmt"
	"github.com/jmcvetta/neoism"
)

func main() {
	neo, _ := neoism.Connect("http://localhost:7474/db/data")

	// 创建一个具有随机id的节点
	nodeId := uuid.New()
	_, err := neo.CreateNode(neoism.Props{"NodeId": nodeId})
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("node created, id", nodeId)

	// 根据id查找节点
	res := []struct {
		Node neoism.Node `json:"nodes"`
	}{}
	err = neo.Cypher(&neoism.CypherQuery{
		Statement:  `MATCH (nodes {NodeId:{NodeId}}) RETURN nodes`,
		Parameters: neoism.Props{"NodeId": nodeId},
		Result:     &res,
	})
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("query executed")

	// 尝试处理查询结果
	if len(res) > 0 {
		// 获取Data - 可行
		fmt.Println(res[0].Node.Data)
		// 调用方法 - 引发错误
		err = res[0].Node.SetProperty("TestProp", "TestValue")
		if err != nil {
			fmt.Println(err)
			return
		}
	}
}

以下是堆栈跟踪的相关部分:

goroutine 1 [running]:
github.com/jmcvetta/neoism.(*entity).SetProperty(0x119abc00, 0x5d3a68, 0x8, 0x5d3a88, 0x9, ...)
        .../src/github.com/jmcvetta/neoism/entity.go:26 +0x104
main.main()
        .../src/nieware/neoprob/neoprob.go:41 +0x4cb
英文:

When trying to call a method of a Node object returned by a call to neoism.CypherQuery, I keep getting "invalid memory address or nil pointer dereference" panics. The query returns something (accessing the Data property of the Node works), but calling any method leads to a panic. The methods have the receiver *Node, not Node, but AFAIK that should work nevertheless? Anyway, I have already tried getting a pointer to the object and calling the method on that, but that didn't work either. I'm really stuck here...

Example code to reproduce the problem (needs neoism and go-uuid packages and a Neo4J DB running on localhost):

package main

import (
	"code.google.com/p/go-uuid/uuid"
	"fmt"
	"github.com/jmcvetta/neoism"
)

func main() {
	neo, _ := neoism.Connect("http://localhost:7474/db/data")

	// create a node with a random id
	nodeId := uuid.New()
	_, err := neo.CreateNode(neoism.Props{"NodeId": nodeId})
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("node created, id", nodeId)

	// find the node by the id
	res := []struct {
		Node neoism.Node `json:"nodes"`
	}{}
	err = neo.Cypher(&neoism.CypherQuery{
		Statement:  `MATCH (nodes {NodeId:{NodeId}}) RETURN nodes`,
		Parameters: neoism.Props{"NodeId": nodeId},
		Result:     &res,
	})
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("query executed")

	// try to work with the query results
	if len(res) > 0 {
		// get Data -> works
		fmt.Println(res[0].Node.Data)
		// call method -> panics
		err = res[0].Node.SetProperty("TestProp", "TestValue")
		if err != nil {
			fmt.Println(err)
			return
		}
	}
}

Here's the relevant part of the stack trace:

goroutine 1 [running]:
github.com/jmcvetta/neoism.(*entity).SetProperty(0x119abc00, 0x5d3a68, 0x8, 0x5d3a88, 0x9, ...)
        .../src/github.com/jmcvetta/neoism/entity.go:26 +0x104
main.main()
        .../src/nieware/neoprob/neoprob.go:41 +0x4cb

答案1

得分: 2

看一下SetProperty方法的源代码:https://github.com/jmcvetta/neoism/blob/master/entity.go#L22

看起来它来自一个嵌入的结构体,实际上并不是Node结构体上的一个方法。嵌入的entity结构体不是一个指针,所以它也不应该为空。

堆栈跟踪显示,恐慌发生在第26行,因为e.Db没有初始化:

resp, err := e.Db.Session.Put(url, &value, nil, &ne)

在调用SetProperty之前设置e.Db可以解决这个问题:

res[0].Node.Db = neo
英文:

Looking at the source for the SetProperty method: https://github.com/jmcvetta/neoism/blob/master/entity.go#L22

It looks like it comes from an embedded struct and is not actually a method on the Node struct. The embedded entity struct is not a pointer however so it also should not be null.

The stack trace shows that the panic occurs at line 26, because e.Db is not initialized:

resp, err := e.Db.Session.Put(url, &value, nil, &ne)

setting e.Db before calling SetProperty solves the problem:

res[0].Node.Db = neo

huangapple
  • 本文由 发表于 2014年12月11日 00:11:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/27405705.html
匿名

发表评论

匿名网友

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

确定