英文:
How to use the struct inside a struct? invalid memory address or nil pointer dereference
问题
我在使用Queue
时遇到了一个恐慌。这是我的结构体:
type RabbitMQ struct {
Connection *amqp.Connection
Channel *amqp.Channel
Queue amqp.Queue // 用于消费者
done chan os.Signal
notifyClose chan *amqp.Error
notifyConfirm chan *amqp.Confirmation
IsConnected bool
alive bool
Done chan os.Signal
Err chan error
Wg *sync.WaitGroup
}
这是原始库中的Queue
结构体:
type Queue struct {
Name string // 服务器确认或生成的名称
Messages int // 未等待确认的消息数
Consumers int // 接收投递的消费者数量
}
在这个函数中,我尝试使用r.Queue
:
func (r *RabbitMQ) InitQueueForConsumer() {
log.Println("inside initqueue")
var err error
r.Queue, err = r.Channel.QueueDeclare(
"", // 名称
false, // 持久化
false, // 未使用时删除
true, // 独占
false, // 不等待
nil, // 参数
)
if err != nil {
log.Printf("failed to declare a queue")
}
log.Println("inside initqueue")
err = r.Channel.QueueBind(
r.Queue.Name,
"",
"logs",
false,
nil,
)
if err != nil {
log.Printf("failed to bind a queue")
}
log.Println("inside initqueue")
}
func (r *RabbitMQ) Consume() {
msgs, err := r.Channel.Consume(
r.Queue.Name,
"",
true,
false,
false,
false,
nil,
)
if err != nil {
log.Printf("failed to register a consumer")
}
forever := make(chan bool)
go func() {
for {
select {
case msg, ok := <-msgs:
if !ok {
log.Printf("something wrong")
return
}
log.Printf("Received message: [%v]\n", msg)
}
}
}()
log.Printf("Waiting for logs")
<-forever
}
我像这样调用这个函数:
rmq := shared.RabbitMQ{}
go rmq.New()
for {
go rmq.InitQueueForConsumer()
}
当我运行时,我得到了以下的恐慌:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x54 pc=0x11c27c6]
goroutine 22 [running]:
github.com/streadway/amqp.(*Channel).send(0x0, 0x1283c78, 0xc0000b0000, 0xc000071e28, 0x100e86a)
/Users/barisertas/go/pkg/mod/github.com/streadway/amqp@v1.0.0/channel.go:157 +0x26
github.com/streadway/amqp.(*Channel).call(0x0, 0x1283c78, 0xc0000b0000, 0xc000071f40, 0x1, 0x1, 0xc000100050, 0x2)
/Users/barisertas/go/pkg/mod/github.com/streadway/amqp@v1.0.0/channel.go:171 +0x5d
github.com/streadway/amqp.(*Channel).QueueDeclare(0x0, 0x0, 0x0, 0x10000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/barisertas/go/pkg/mod/github.com/streadway/amqp@v1.0.0/channel.go:767 +0x150
github.com/bariis/rd/shared.(*RabbitMQ).InitQueueForConsumer(0xc000152000)
/Users/barisertas/workspace/golang-exercises/rd/shared/rabbitmq.go:151 +0x90
created by main.main
/Users/barisertas/workspace/golang-exercises/rd/receiver1/main.go:67 +0x76
exit status 2
这是原始库中queueDeclare
函数的返回值:
func (ch *Channel) QueueDeclare(name string, durable, autoDelete, exclusive, noWait bool, args Table) (Queue, error) {
if err := args.Validate(); err != nil {
return Queue{}, err
}
req := &queueDeclare{
Queue: name,
Passive: false,
Durable: durable,
AutoDelete: autoDelete,
Exclusive: exclusive,
NoWait: noWait,
Arguments: args,
}
res := &queueDeclareOk{}
if err := ch.call(req, res); err != nil {
return Queue{}, err
}
if req.wait() {
return Queue{
Name: res.Queue,
Messages: int(res.MessageCount),
Consumers: int(res.ConsumerCount),
}, nil
}
return Queue{Name: name}, nil
}
我尝试了各种指针、地址等的组合,我尝试在New
函数中初始化它,因为它在QueueDeclare
函数之前被调用,我以为它不会引发恐慌,但没有解决方案。我该如何正确地做这个?
英文:
I am getting an panic when I want to use Queue
. This is my struct:
type RabbitMQ struct {
Connection *amqp.Connection
Channel *amqp.Channel
Queue amqp.Queue // for consumer
done chan os.Signal
notifyClose chan *amqp.Error
notifyConfirm chan *amqp.Confirmation
IsConnected bool
alive bool
Done chan os.Signal
Err chan error
Wg *sync.WaitGroup
}
This is the original Queue
struct inside original library.
type Queue struct {
Name string // server confirmed or generated name
Messages int // count of messages not awaiting acknowledgment
Consumers int // number of consumers receiving deliveries
}
Here in this function I am trying to use r.Queue
by:
func (r *RabbitMQ) InitQueueForConsumer() {
log.Println("inside initqueue")
var err error
r.Queue, err = r.Channel.QueueDeclare(
"", // name
false, // durable
false, // delete when unused
true, // exclusive
false, // no-wait
nil, // arguments
)
if err != nil {
log.Printf("failed to declare a queue")
}
log.Println("inside initqueue")
err = r.Channel.QueueBind(
r.Queue.Name,
"",
"logs",
false,
nil,
)
if err != nil {
log.Printf("failed to bind a queue")
}
log.Println("inside initqueue")
}
func (r *RabbitMQ) Consume() {
msgs, err := r.Channel.Consume(
r.Queue.Name,
"",
true,
false,
false,
false,
nil,
)
if err != nil {
log.Printf("failed to register a consumer")
}
forever := make(chan bool)
go func() {
for {
select {
case msg, ok := <-msgs:
if !ok {
log.Printf("something wrong")
return
}
log.Printf("Received message: [%v]\n", msg)
}
}
}()
log.Printf("Waiting for logs")
<-forever
}
I am calling this function like:
rmq := shared.RabbitMQ{}
go rmq.New()
for {
go rmq.InitQueueForConsumer()
}
When I run I am getting the panic as follows:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x54 pc=0x11c27c6]
goroutine 22 [running]:
github.com/streadway/amqp.(*Channel).send(0x0, 0x1283c78, 0xc0000b0000, 0xc000071e28, 0x100e86a)
/Users/barisertas/go/pkg/mod/github.com/streadway/amqp@v1.0.0/channel.go:157 +0x26
github.com/streadway/amqp.(*Channel).call(0x0, 0x1283c78, 0xc0000b0000, 0xc000071f40, 0x1, 0x1, 0xc000100050, 0x2)
/Users/barisertas/go/pkg/mod/github.com/streadway/amqp@v1.0.0/channel.go:171 +0x5d
github.com/streadway/amqp.(*Channel).QueueDeclare(0x0, 0x0, 0x0, 0x10000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
/Users/barisertas/go/pkg/mod/github.com/streadway/amqp@v1.0.0/channel.go:767 +0x150
github.com/bariis/rd/shared.(*RabbitMQ).InitQueueForConsumer(0xc000152000)
/Users/barisertas/workspace/golang-exercises/rd/shared/rabbitmq.go:151 +0x90
created by main.main
/Users/barisertas/workspace/golang-exercises/rd/receiver1/main.go:67 +0x76
exit status 2
And this what queueDeclare
function returns from the original library:
func (ch *Channel) QueueDeclare(name string, durable, autoDelete, exclusive, noWait bool, args Table) (Queue, error) {
if err := args.Validate(); err != nil {
return Queue{}, err
}
req := &queueDeclare{
Queue: name,
Passive: false,
Durable: durable,
AutoDelete: autoDelete,
Exclusive: exclusive,
NoWait: noWait,
Arguments: args,
}
res := &queueDeclareOk{}
if err := ch.call(req, res); err != nil {
return Queue{}, err
}
if req.wait() {
return Queue{
Name: res.Queue,
Messages: int(res.MessageCount),
Consumers: int(res.ConsumerCount),
}, nil
}
return Queue{Name: name}, nil
}
I have tried every combination did with pointer, address etc. I tried to initialize it New
function since it's called before QueueDeclare
function I though It won't give panic but no solution. How can I do this properly?
答案1
得分: 2
rmq := shared.RabbitMQ{}
在 RabbitMQ{}
中没有初始化任何字段。它为所有字段分配了零(默认)值。
指针的零(默认)值是nil。点击这里了解更多
因此,在 InitQueueForConsumer()
中,RabbitMQ{}
内部的所有指针都是nil。所以,当你在访问它们时,肯定会出现 runtime error: invalid memory address or nil pointer dereference
的错误。
在使用之前,请至少初始化指针字段。
通道的零(默认)值也是nil。参考 - 为什么Go语言中会有nil通道。
但是,向/从nil通道发送/接收不会引发错误,而是永远阻塞。关闭一个nil通道会引发 runtime error: close of nil channel
的错误。
英文:
rmq := shared.RabbitMQ{}
not initialising any fields in RabbitMQ{}
. It assigns zero (default) values for all fields.
Zero (default) value of a pointer is nil. tour here
So all pointers are nil inside RabbitMQ{}
. So, when you going to access them in InitQueueForConsumer()
, sure it will panic with runtime error: invalid memory address or nil pointer dereference
.
First Initialise atleast pointer fields before using them.
Zero (default) value of a channel is also nil. refer -why-are-there-nil-channels-in-go.
But send to/receive from a nil channel not panics, but blocks forever. Closing a nil channel will panic with runtime error: close of nil channel
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论