# #go #pointers #struct #rabbitmq
Вопрос:
У меня возникает паника, когда я хочу использовать Queue
. Это моя структура:
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
}
Это оригинальная Queue
структура внутри оригинальной библиотеки.
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
}
Здесь, в этой функции, я пытаюсь использовать r.Queue
:
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
}
Я вызываю эту функцию следующим образом:
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 := amp;queueDeclare{
Queue: name,
Passive: false,
Durable: durable,
AutoDelete: autoDelete,
Exclusive: exclusive,
NoWait: noWait,
Arguments: args,
}
res := amp;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, хотя это не вызовет паники, но не решит проблему. Как я могу сделать это правильно?
Комментарии:
1. Я не вижу кода, который создал соединение и канал из него.
Ответ №1:
rmq := shared.RabbitMQ{}
не инициализируя никаких полей внутри RabbitMQ{}
. Он присваивает нулевые значения (по умолчанию) для всех полей.
Нулевое (по умолчанию) значение указателя равно нулю. экскурсия здесь
Таким образом, все указатели внутри равны нулю RabbitMQ{}
. Так что, когда вы собираетесь получить к ним доступ InitQueueForConsumer()
, обязательно запаникуйте runtime error: invalid memory address or nil pointer dereference
.
Сначала инициализируйте по крайней мере поля указателя, прежде чем использовать их.
Нулевое (по умолчанию) значение канала также равно нулю. обратитесь —почему-нет-каналов-в-ходу.
Но отправка/получение с нулевого канала не паникует, а блокируется навсегда. Закрытие нулевого канала вызовет панику с runtime error: close of nil channel