在Go中获取列表中结构体的指针

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

Getting pointer to struct in list in Go

问题

我正在尝试创建一个函数,该函数将查找一个电梯结构(类型为container/list的列表)并返回具有正确IP地址的电梯的指针(该程序旨在控制多台计算机上的电梯),如果没有具有此地址的电梯,则返回nil。

以下是函数代码:

func (e *ElevatorList) IPIsInList(ip string) *elevator {
    for c := e.Elevators.Front(); c != nil; c = c.Next() {
        if c.Value.(*elevator).Ip == ip {
            return c.Value.(*elevator)
        }
    }
    return nil
}

我认为第一个返回行中的类型转换看起来有点可疑,但这是为数不多没有引起编译器错误的实现之一。当我运行程序时,首先会得到其他函数的输出,当调用IPIsInList()函数时,我会得到以下输出:

panic: interface conversion: interface is **main.elevator, not main.elevator

runtime.panic+0xac /home/fredrik/go/src/pkg/runtime/proc.c:1254
runtime.panic(0x4937a8, 0xf84002aaf0)
assertE2Tret+0x11d /home/fredrik/go/src/pkg/runtime/iface.c:312
assertE2Tret(0x4927f8, 0x45e6d8, 0xf8400004f0, 0x7fbae00c1ed8, 0x10, ...)
runtime.assertE2T+0x50 /home/fredrik/go/src/pkg/runtime/iface.c:292
runtime.assertE2T(0x4927f8, 0x45e6d8, 0xf8400004f0, 0x28)
main.(*ElevatorList).IPIsInList+0x5b /home/fredrik/Dropbox/Programmering/go/listtest/elevatorList.go:72
main.(*ElevatorList).IPIsInList(0xf8400001c8, 0x4a806c, 0x2e3332310000000f, 0x0, 0x0, ...)
main.main+0x1f3 /home/fredrik/Dropbox/Programmering/go/listtest/main.go:53
main.main()
runtime.mainstart+0xf /home/fredrik/go/src/pkg/runtime/amd64/asm.s:78
runtime.mainstart()
runtime.goexit /home/fredrik/go/src/pkg/runtime/proc.c:246
runtime.goexit()
----- goroutine created by -----
_rt0_amd64+0xc9 /home/fredrik/go/src/pkg/runtime/amd64/asm.s:65

应该如何解决这个问题?我已经多次重写了这个函数,我认为使用c.Value.(elevator)和/或c.Value.(*elevator)是导致问题的原因。以下是elevatorElevatorList的结构体:

type elevator struct {
    Ip             string
    OrderList      [FLOORS][3]int32
    Floor          int32
    Dir            int
    Ms_since_ping  int32
}

type ElevatorList struct {
    Elevators *list.List
}

使用以下函数将elevator添加到列表中:

func (e *ElevatorList) AddToList(newElevator *elevator) {
    e.Elevators.PushBack(&newElevator)
}
英文:

I'm trying to make a function that will look through a list (type container/list) of elevator-structs and return a pointer to the elevator that has the correct ip-address (the program is meant to control elevators on multiple computers) or nil if there is no elevator with this address.

Here is the function code:

func (e *ElevatorList)IPIsInList(ip string) *elevator{
    for c := e.Elevators.Front(); c != nil; c = c.Next(){
        if(c.Value.(elevator).Ip == ip){
                return c.Value.(*elevator)
	    }
    }
    return nil
}

I think the casting in the first return line looks kind of fishy but it's one of the few implementations that hasn't caused compiler errors. When I run the program I first get the output from other functions, and when the IPIsInList() function is called i get the following:

panic: interface conversion: interface is **main.elevator, not main.elevator

runtime.panic+0xac /home/fredrik/go/src/pkg/runtime/proc.c:1254
runtime.panic(0x4937a8, 0xf84002aaf0)
assertE2Tret+0x11d /home/fredrik/go/src/pkg/runtime/iface.c:312
assertE2Tret(0x4927f8, 0x45e6d8, 0xf8400004f0, 0x7fbae00c1ed8, 0x10, ...)
runtime.assertE2T+0x50 /home/fredrik/go/src/pkg/runtime/iface.c:292
runtime.assertE2T(0x4927f8, 0x45e6d8, 0xf8400004f0, 0x28)
main.(*ElevatorList).IPIsInList+0x5b /home/fredrik/Dropbox/Programmering/go/listtest/elevatorList.go:72
main.(*ElevatorList).IPIsInList(0xf8400001c8, 0x4a806c, 0x2e3332310000000f, 0x0, 0x0, ...)
main.main+0x1f3 /home/fredrik/Dropbox/Programmering/go/listtest/main.go:53
main.main()
runtime.mainstart+0xf /home/fredrik/go/src/pkg/runtime/amd64/asm.s:78
runtime.mainstart()
runtime.goexit /home/fredrik/go/src/pkg/runtime/proc.c:246
runtime.goexit()
----- goroutine created by -----
_rt0_amd64+0xc9 /home/fredrik/go/src/pkg/runtime/amd64/asm.s:65

How should this be done? I have rewritten the function many times and I think it's the use of c.Value.(elevator) and/or c.Value.(*elevator) that's causing the problem. Here are the structs for elevator and Elevator_list:

type elevator struct {
Ip string
OrderList [FLOORS][3]int32
Floor int32
Dir int
Ms_since_ping int32
}

type ElevatorList struct {

Elevators *list.List

}

The elevators are added to the list with the function

func (e *ElevatorList) AddToList(newElevator *elevator){
e.Elevators.PushBack(&newElevator)

}

答案1

得分: 2

显然,container/list可以工作,但是对于“应该如何做?”的答案可能是“不要使用container/list,只使用普通的切片。”这是一个替代版本:

package main

import "fmt"

const FLOORS = 6

type elevator struct {
    Ip            string
    OrderList     [FLOORS][3]int32
    Floor         int32
    Dir           int
    Ms_since_ping int32
}

type ElevatorList []*elevator

func (list ElevatorList) IPIsInList(ip string) *elevator {
    for _, e := range list {
        if e.Ip == ip {
            return e
        }
    }
    return nil
}

func (list ElevatorList) PrintAll() {
    fmt.Println(len(list), "items in list:")
    for _, e := range list {
        fmt.Println("  ", *e)
    }
}

func main() {
    var list ElevatorList
    list = append(list, &elevator{Ip: "1.1.1.1"})
    list = append(list, &elevator{Ip: "2.2.2.2"})
    list.PrintAll()
    list.PrintOne("1.1.1.1")
}

func (list ElevatorList) PrintOne(ip string) {
    if e := list.IPIsInList(ip); e == nil {
        fmt.Println(ip, "not found")
    } else {
        fmt.Println("found:", *e)
    }
}

请注意,ElevatorList不需要是一个结构体。我完全抛弃了AddToList方法。甚至可以抛弃IPIsInList。没有它,PrintOne方法看起来并不复杂。

func (list ElevatorList) PrintOne(ip string) {
    for _, e := range list {
        if e.Ip == ip {
            fmt.Println("found:", *e)
        }
    }
    fmt.Println(ip, "not found")
}
英文:

Obviously container/list works, but the answer to "How should this be done?" may be "don't use container/list, just use plain slices." Here's an alternative version:

package main

import "fmt"

const FLOORS = 6

type elevator struct {
    Ip            string
    OrderList     [FLOORS][3]int32
    Floor         int32
    Dir           int
    Ms_since_ping int32
}

type ElevatorList []*elevator

func (list ElevatorList) IPIsInList(ip string) *elevator {
    for _, e := range list {
        if e.Ip == ip {
            return e
        }
    }
    return nil
}

func (list ElevatorList) PrintAll() {
    fmt.Println(len(list), "items in list:")
    for _, e := range list {
        fmt.Println("  ", *e)
    }
}

func main() {
    var list ElevatorList
    list = append(list, &elevator{Ip: "1.1.1.1"})
    list = append(list, &elevator{Ip: "2.2.2.2"})
    list.PrintAll()
    list.PrintOne("1.1.1.1")
}

func (list ElevatorList) PrintOne(ip string) {
    if e := list.IPIsInList(ip); e == nil {
        fmt.Println(ip, "not found")
    } else {
        fmt.Println("found:", *e)
    }
}

Note that there was no need for ElevatorList to be a struct. I completely tossed the AddToList method. You might even toss IPIsInList. Without it the method PrintOne doesn't look any more complex.

func (list ElevatorList) PrintOne(ip string) {
    for _, e := range list {
        if e.Ip == ip {
            fmt.Println("found:", *e)
        }
    }
    fmt.Println(ip, "not found")
}

答案2

得分: 1

在你的add函数中,你正在获取一个elevator并在将其放入列表之前获取指针的地址。在你的retrieve函数中,你断言类型是elevator两次。一次在if语句中,一次在返回语句中。它们都与真实类型(elevator)不一致。你的if语句是第一个,所以它会抛出错误,解释变量是elevator而不是elevator:

panic: interface conversion: interface is **main.elevator, not main.elevator

我会做两件事。首先,将*elevator添加到列表中,而不是**elevator:

func (e *ElevatorList) AddToList(newElevator *elevator){
    e.Elevators.PushBack(newElevator)
}

接下来,我会更改if语句,使其对*elevator进行类型断言,而不是elevator:

if(*(c.Value.(*elevator)).Ip == ip){
英文:

In your add function, you are taking a *elevator and taking the address of the pointer before putting it in your list. In your retrieve function you are asserting that the type is an *elevator twice. Once in the if statement and once in the return. Both of them disagree with the true type (**elevator). Your if statement is the first one so it panics explaining that the variable is an **elevator and not an elevator:

panic: interface conversion: interface is **main.elevator, not main.elevator

I would do two things. First, add *elevators to the list, not **elevators:

func (e *ElevatorList) AddToList(newElevator *elevator){
    e.Elevators.PushBack(newElevator)
}

Next, I would change the if statement so it does a type assertion to *elevator, not elevator:

if(*(c.Value.(*elevator)).Ip == ip){

答案3

得分: 0

例如,

package main

import (
	"container/list"
	"fmt"
)

type Elevator struct {
	Ip string
}

type Elevators struct {
	List *list.List
}

func (e *Elevators) AddToList(elevator *Elevator) {
	e.List.PushBack(elevator)
}

func (e *Elevators) IPIsInList(ip string) *Elevator {
	for c := e.List.Front(); c != nil; c = c.Next() {
		if c.Value.(*Elevator).Ip == ip {
			return c.Value.(*Elevator)
		}
	}
	return nil
}

func main() {
	elevators := Elevators{list.New()}
	ip := "192.168.0.10"
	elevator := Elevator{Ip: ip}
	elevators.AddToList(&elevator)
	eip := elevators.IPIsInList(ip)
	if eip != nil {
		fmt.Println(*eip)
	}
}

输出:

{192.168.0.10}
英文:

For example,

package main

import (
	"container/list"
	"fmt"
)

type Elevator struct {
	Ip string
}

type Elevators struct {
	List *list.List
}

func (e *Elevators) AddToList(elevator *Elevator) {
	e.List.PushBack(elevator)
}

func (e *Elevators) IPIsInList(ip string) *Elevator {
	for c := e.List.Front(); c != nil; c = c.Next() {
		if c.Value.(*Elevator).Ip == ip {
			return c.Value.(*Elevator)
		}
	}
	return nil
}

func main() {
	elevators := Elevators{list.New()}
	ip := "192.168.0.10"
	elevator := Elevator{Ip: ip}
	elevators.AddToList(&elevator)
	eip := elevators.IPIsInList(ip)
	if eip != nil {
		fmt.Println(*eip)
	}
}

Output:

{192.168.0.10}

huangapple
  • 本文由 发表于 2012年3月15日 06:24:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/9711223.html
匿名

发表评论

匿名网友

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

确定