在导入包中定义struct时如何使用go接收器
currently working with the vishvananda/netns
package trying to extract routes from a specific network namespace.
There is a defined Handle
struct which is returned when I request a 'handle' for a specific network namespace. As such:
func NewHandleAt(ns netns.NsHandle, nlFamilies ...int) (*Handle, error)
This is then a receiver argument (?) to a function that requires that handle,
func (h *Handle) LinkList() ([]Link, error)
I'm new to go and not sure how to tie these together. I'm stuck with:
func (h *Handle) showInts() {
int, err := h.netlink.LinkList()
if err != nil {
log.Fatal(err)
}
for i, r := range int {
log.Printf("%d: %s", i, r.Attrs().Name)
}
}
func main() {
ints, err := netlink.LinkList()
if err != nil {
log.Fatal(err)
}
for i, r := range ints {
log.Printf("%d: %s", i, r.Attrs().Name)
}
pid, err := netns.GetFromPid(9097)
if err != nil {
log.Fatal(err)
}
netlink.NewHandleAt(pid)
showInts()
}
当前正在使用 有一个已定义的 我是新手,不确定如何将它们绑在一起。 我陷入困境: p>
vishvananda / netns code>包,试图从特定的网络名称空间提取路由 。 p>
Handle code>结构,当我请求特定网络名称空间的“句柄”时会返回该结构。 这样: p>
func NewHandleAt(ns netns.NsHandle,nlFamilies ... int)(* Handle,error) code> p>
这是需要该句柄的函数的接收方参数(?) p>
func(h * Handle)LinkList()([]链接,错误) p>
func(h * Handle)showInts(){
int,err:= h.netlink.LinkList()
如果err!= nil {
log.Fatal(err)
}
for i,r:= range int {
log.Printf(“%d:%s”,i,r.Attrs()。Name)
}
}
func main(){
ints,err:= netlink.LinkList()
if err!= nil {
log.Fatal(err)
}
for i,r:=范围整数{
log.Printf(“%d:%s”,i,r.Attrs()。Name)
}
pid,err == netns.GetFromPid(9097)
if err!= nil {
log.Fatal(err)
}
netlink.NewHandleAt(pid)
showInts()
}
code> pre>
Update
While writing the original answer, touched on a number of things, without any clear structure, so here's a more structured version:
Depending on what you're actually asking (ie "How do I add a receiver function/method to an exported type", or "What the hell is a receiver function"), the answers are as follows:
How do I add a receiver function to an exported type?
Easy, same as you do with any other type. You were close, in fact. This doesn't work:
func (h *Handler) showInts() {}
Because you're adding a method to the Handler
type in your package. Given you have a main
function, that would be the main
package. You're trying to add it to the netlink.Handler
type instead. In which case, this will work:
func (h *netlink.Handler) showInts(){}
The type is netlink.Handler
in your main package after all... This, however will not work. The compiler will refuse to compile, telling you: "Cannot define new methods on non-local type". This is easily mitigated, though, by creating a new type, and add the method there:
type MyHandler netlink.Handler
func (h *MyHandler) showInts(){}
Be that as it may, the last 2 lines in your code strike me as wrong.
Given that NewHandleAt
returns (*Handle, error)
, and netlink.Handle
is a receiver argument, the correct way would be:
var mh *MyHandle
if h, err := netlink.NewHandleAt(pid); err != nil {
log.Fatal(err) // something went wrong
} else {
mh = (*MyHandle)(h)
}
mh.showInts() // call showInts on mh, which is of type *MyHandle
The fact that you've "wrapped" the external type in a custom type does mean you'll find yourself casting the same thing quite a lot. Say netlink.Handle
has a Test
method, and you want to call it inside showInts
:
func (h *MyHandle) showInts() {
nh := (*netlink.Handle)(h) //cast required
nh.Test()
}
I'd also change the varname from pid
to nsh
or something, because it's a NsHandle
, and not a pid
after all...
What is a receiver argument?
Because you wrote this:
This is then a receiver argument (?) to a function that requires that handle,
I get the impression you're not entirely clear on what a receiver argument is. Put simply, it's like a function argument, but instead of an argument that is just passed to a function, it's an argument that holds the object/value on which the function is called. Basically, it's the "instance" on which the function/method is called. Think of it as the this
keyword in many OOP languages:
func (h *MyHandle) showInts() {
return
}
In something like C++ would be
class MyHandle : Handle
{
public:
void showInts(void) { return; } // replace h with this
}
There are significant differences, however:
- The receiver argument can be a pointer, or a value - in case of a value receiver, the method cannot modify the receiver value
- There's no such thing as private, public, or protected... at least not in the traditional OO way
- ...
There's quite a few differences, perhaps consider going through the golang tour. The stuff about go methods can be found here
Other issues/weird things
After looking at your code again, I'm really not sure whether this is correct:
h.netlink.LinkList()
In your main
function, you call netlink.LinkList()
. h
is a *netlink.Handler
. If you need to call the netlink.LinkList
function, it's highly likely h.netlink.LinkList
is not what you want to do. Instead, you should simply call netlink.LinkList()
.
That's assuming you need to call the function in the first place.
Given that you've already called it in the main
function, why not pass it as an argument?
//in main:
ints, err := netlink.LinkList()
//...
h.showInts(ints)
func (h *MyHandle)showInts(ll []netlink.Link) {
}
Thanks Elias, awesome answer!
From that, I've written the following code which will list interfaces belonging to a specific namespace. Thanks!
package main
import (
"github.com/vishvananda/netns"
"github.com/vishvananda/netlink"
"log"
)
type NSHandle netlink.Handle
func (h *NSHandle) showInts() {
nh := (*netlink.Handle)(h) //cast required
int, err := nh.LinkList()
if err != nil {
log.Fatal(err)
}
log.Printf("Namespace Ints:")
for i, r := range int {
log.Printf("%d: %s", i, r.Attrs().Name)
}
}
func getNSFromPID(pid int) (*NSHandle) {
hpid, err := netns.GetFromPid(9115)
if err != nil {
log.Fatal(err)
}
var nsh *NSHandle
if h, err := netlink.NewHandleAt(hpid); err != nil {
log.Fatal(err) // something went wrong
} else {
nsh = (*NSHandle)(h)
}
return nsh
}
func main() {
getNSFromPID(9115).showInts()
}