在地图中的函数是<nil>。

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

function in map is <nil>

问题

我正在尝试在Go语言中构建一个简单的路由器。我在一个结构体上有一个get方法,应该将回调传递给Get路由映射,其中URL作为键。似乎fmt.Println(urlCallback)返回了一个空值,并且如果我尝试调用它,会导致运行时恐慌。作为一个来自JavaScript背景的人,我刚刚开始理解指针等内容,并且觉得可能与此有关。如果有人能告诉我为什么传递的函数是空值,那就太好了。

这是我的"Router"包:

package Router

import (
	"fmt"
	"net/http"
	"net/url"
	"log"
)

type Res http.ResponseWriter
type Req *http.Request

type RouteMap map[*url.URL]func(Res, Req) 
type MethodMap map[string]RouteMap

type Router struct {
	Methods MethodMap
}

func (router *Router) Get(urlString string, callback func(Res, Req)) {
	parsedUrl, err := url.Parse(urlString)

	if(err != nil) {
		panic(err)
	}

	fmt.Println(parsedUrl)

	router.Methods["GET"][parsedUrl] = callback
}

func (router *Router) initMaps() {
	router.Methods = MethodMap{}
	router.Methods["GET"] = RouteMap{}
}

func (router Router) determineHandler(res http.ResponseWriter, req *http.Request) {
	fmt.Println(req.URL)
	fmt.Println(req.Method)

	methodMap := router.Methods[req.Method]
	urlCallback := methodMap[req.URL]

	fmt.Println(methodMap)
	fmt.Println(urlCallback)
}

func (router Router) Serve(host string, port string) {
	fullHost := host + ":" + port

	fmt.Println("Router is now serving to:" + fullHost)
	http.HandleFunc("/", router.determineHandler)
	
	err := http.ListenAndServe(fullHost, nil)
	
	if err == nil {
		fmt.Println("Router is now serving to:" + fullHost)
	} else {
		fmt.Println("An error occurred")
		log.Fatal(err)
	}
}


func NewRouter() Router {
	newRouter := Router{}
	newRouter.initMaps()

	return newRouter
}

这是我的main函数:

package main

import (
	"./router"
	"fmt"
)

func main() {
	router := Router.NewRouter()
	
	router.Get("/test", func(Router.Res, Router.Req) {
		fmt.Println("In test woohooo!")
	})

	router.Serve("localhost", "8888")
}
英文:

I am trying to build a simple router in Go, I have a get method on a struct that should be passing a callback to the Get route map with the url as the key, it seems that fmt.Println(urlCallback) is returning a nil value and causes a runtime panic if i tried to call it, coming from a javascript background I am only just coming to grips with pointers and the like and feel it may have something to do with this,if someone could tell me why the passed func is nil that would be great.

Here is my "Router" package.

package Router
import (
&quot;fmt&quot;
&quot;net/http&quot;
&quot;net/url&quot;
&quot;log&quot;
)
type Res http.ResponseWriter
type Req *http.Request
type RouteMap map[*url.URL]func(Res, Req) 
type MethodMap map[string]RouteMap
type Router struct {
Methods MethodMap
}
func (router *Router) Get(urlString string, callback func(Res, Req)) {
parsedUrl, err := url.Parse(urlString)
if(err != nil) {
panic(err)
}
fmt.Println(parsedUrl)
router.Methods[&quot;GET&quot;][parsedUrl] = callback
}
func (router *Router) initMaps() {
router.Methods = MethodMap{}
router.Methods[&quot;GET&quot;] = RouteMap{}
}
func (router Router) determineHandler(res http.ResponseWriter, req *http.Request) {
fmt.Println(req.URL)
fmt.Println(req.Method)
methodMap := router.Methods[req.Method]
urlCallback := methodMap[req.URL]
fmt.Println(methodMap)
fmt.Println(urlCallback)
}
func (router Router) Serve(host string, port string) {
fullHost := host + &quot;:&quot; + port
fmt.Println(&quot;Router is now serving to:&quot; + fullHost)
http.HandleFunc(&quot;/&quot;, router.determineHandler)
err := http.ListenAndServe(fullHost, nil)
if err == nil {
fmt.Println(&quot;Router is now serving to:&quot; + fullHost)
} else {
fmt.Println(&quot;An error occurred&quot;)
log.Fatal(err)
}
}
func NewRouter() Router {
newRouter := Router{}
newRouter.initMaps()
return newRouter
}

and my main.

package main
import (
&quot;./router&quot;
&quot;fmt&quot;
)
func main() {
router := Router.NewRouter()
router.Get(&quot;/test&quot;, func(Router.Res, Router.Req) {
fmt.Println(&quot;In test woohooo!&quot;)
})
router.Serve(&quot;localhost&quot;, &quot;8888&quot;)
}

答案1

得分: 6

你正在使用*URL.url对象作为映射键。由于两个不同的对象不会相同,所以你无法再次访问该路径的键。它会出现错误,因为

urlCallback := methodMap[req.URL]

不是一个现有的键,所以你正在访问一个空值。在这种情况下,你可能想要使用URL.url对象的Path属性。

所以你可以这样写:

type RouteMap map[string]func(Res, Req)

Get()函数中:

router.Methods["GET"][parsedUrl.Path] = callback

对于determineRouter()函数,你可以这样做:

urlCallback, exists := methodMap[req.URL.Path]
if exists != false {
urlCallback(res, req)
}

这样在调用之前会检查键是否存在。

英文:

You are using *URL.url objects for map keys. Since two different objects won't be the same, you can't access the key for that path again. It's panicking because

urlCallback := methodMap[req.URL]

isn't an existing key, and so you're accessing a nil value. What you probably want to do in this case is use the Path property of the URL.url object.

So you'd have:

type RouteMap map[string]func(Res, Req)

In Get():

router.Methods[&quot;GET&quot;][parsedUrl.Path] = callback

For determineRouter(), you can do this:

urlCallback, exists := methodMap[req.URL.Path]
if exists != false {
urlCallback(res, req)
}

This adds a check to see if the key exists before it tries to call it.

huangapple
  • 本文由 发表于 2015年1月10日 11:59:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/27872735.html
匿名

发表评论

匿名网友

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

确定