调用函数位于内存地址的func。

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

Call func at memory address

问题

我有一个以结构体为键、函数为值的映射表,当我根据给定的键检索值时,我想调用这个函数。

map[struct]func

map[
    {contact %!s(int=1)}:%!s(main.Controller=0x4c7b50) 
    {services/basket %!s(int=2)}:%!s(main.Controller=0x4c7ad0) 
    {categories %!s(int=1)}:%!s(main.Controller=0x4c7ae0) 
    {categories/{category} %!s(int=2)}:%!s(main.Controller=0x4c7af0)
    {categories/{category}/{product} %!s(int=3)}:%!s(main.Controller=0x4c7b00) 
    {basket %!s(int=1)}:%!s(main.Controller=0x4c7b10) 
    {checkout %!s(int=1)}:%!s(main.Controller=0x4c7b40) 
    {sitemap %!s(int=1)}:%!s(main.Controller=0x4c7b30) 
    {services/order %!s(int=2)}:%!s(main.Controller=0x4c7ac0) 
    {services/image %!s(int=2)}:%!s(main.Controller=0x4c7b20) 
    {/ %!s(int=1)}:%!s(main.Controller=0x4c7a00)
]

c := RouteMap[struct]

如果我使用fmt.Printf("%s", c),我会得到内存地址,如何调用该地址上的函数?

我尝试了c(),但是会导致运行时错误:

%s
0x4c7b10%s
<nil>panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x0 pc=0x4c76f4]

goroutine 5 [running]:
main.RequestHandler(0x577ce0, 0xc042004018)
        C:/Users/mon/Desktop/server.go:91 +0x684
created by main.main
        C:/Users/mon/Desktop/server.go:41 +0x2a0

示例代码:

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"net"
	"strings"
	"time"
)

var RouteMap = make(map[PathIdentifier]Controller)

func main() {
	ln, err := net.Listen("tcp", ":8080")
	if err != nil {
		// 处理错误
	}

	MapRoute("/", HomeController)
	MapRoute("categories", CategoriesController)
	MapRoute("categories/{category}", CategoryController)
	MapRoute("categories/{category}/{product}", CategoryProductController)
	MapRoute("basket", BasketController)

	MapRoute("checkout", CheckoutController)
	MapRoute("sitemap", SitemapController)
	MapRoute("contact", ContactController)

	MapRoute("services/order", OrderServiceController)
	MapRoute("services/basket", BasketServiceController)
	MapRoute("services/image", ImageServiceController)

	fmt.Printf("%s\n", RouteMap)

	for {
		conn, err := ln.Accept()
		if err != nil {
			// 处理错误
		}
		go RequestHandler(conn)
	}
}

// ----------------------- 请求和响应 ---------------------------

func ParseQueryString() {}

func ParsePostData() {}

func ResponseHeaders() {}

func ParseRequestHeaders() {}

func RequestHandler(conn net.Conn) {
	CrLf := "\r\n"
	Terminator := CrLf + CrLf

	defer func() {
		//fmt.Println("Closing connection...")
		conn.Close()
	}()

	timeoutDuration := 10 * time.Second
	bufReader := bufio.NewReader(conn)

	conn.SetReadDeadline(time.Now().Add(timeoutDuration))

	requestBytes, err := bufReader.ReadBytes('\n')
	if err != nil {
		fmt.Println(err)
		return
	}

	requestTokens := bytes.Split(requestBytes, []byte(" "))

	requestMethod := string(requestTokens[0])
	requestPath := string(requestTokens[1])
	//requestHTTPVersion := string(requestTokens[2])

	if requestMethod == "GET" {
		// 解析路径
		pathTokens := strings.Split(requestPath, "/")
		segments := len(pathTokens)

		key := PathIdentifier{path: "categories/{category}/{product}", segments: (segments - 1)}
		c := RouteMap[key]

		fmt.Print("%s\n", c)

	}

	document := []byte("HTTP/1.1 200 OK" + CrLf + "Date: Mon, 27 Jul 2009 12:28:53 GMT" + CrLf + "Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT" + CrLf + "Content-Length: 49" + CrLf + "Content-Type: text/html" + CrLf + "Connection: Closed" + Terminator + "<html><body><h1>Hello, World!</h1></body></html>" + Terminator)

	conn.Write(document)
}

// ----------------------------- 控制器 -----------------------------

type Controller func()

type PathIdentifier struct {
	path     string
	segments int
}

func MapRoute(view string, controller Controller) {
	if controller != nil {

		if view != "/" {
			pathTokens := strings.Split(view, "/")

			key := PathIdentifier{path: view, segments: len(pathTokens)}
			RouteMap[key] = controller
			return
		}

		key := PathIdentifier{path: view, segments: 1}
		RouteMap[key] = controller
	}
}

func HomeController() {
	fmt.Print("调用 HomeController。\n")
}

func OrderServiceController() {

}

func BasketServiceController() {

}

func CategoriesController() {

}

func CategoryController() {

}

func CategoryProductsController() {

}

func CategoryProductController() {

}

func BasketController() {

}

func ImageServiceController() {

}

func SitemapController() {

}

func CheckoutController() {

}

func ContactController() {

}

以上是你要翻译的内容。

英文:

I have a map with a struct as key and a func as value, I would like to call the func when I retrieve the value for a given key

map[struct]func
map[
{contact %!s(int=1)}:%!s(main.Controller=0x4c7b50) 
{services/basket %!s(int=2)}:%!s(main.Controller=0x4c7ad0) 
{categories %!s(int=1)}:%!s(main.Controller=0x4c7ae0) 
{categories/{category} %!s(int=2)}:%!s(main.Controller=0x4c7af0)
{categories/{category}/{product} %!s(int=3)}:%!s(main.Controller=0x4c7b00) 
{basket %!s(int=1)}:%!s(main.Controller=0x4c7b10) 
{checkout %!s(int=1)}:%!s(main.Controller=0x4c7b40) 
{sitemap %!s(int=1)}:%!s(main.Controller=0x4c7b30) 
{services/order %!s(int=2)}:%!s(main.Controller=0x4c7ac0) 
{services/image %!s(int=2)}:%!s(main.Controller=0x4c7b20) 
{/ %!s(int=1)}:%!s(main.Controller=0x4c7a00)
]
c := RouteMap[struct]

If I fmt.Printf(&quot;%s&quot;, c) I get the memory address, how do I invoke the func at the address?

I have tried c() but that gives a runtime error:

%s
0x4c7b10%s
&lt;nil&gt;panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x0 pc=0x4c76f4]
goroutine 5 [running]:
main.RequestHandler(0x577ce0, 0xc042004018)
C:/Users/mon/Desktop/server.go:91 +0x684
created by main.main
C:/Users/mon/Desktop/server.go:41 +0x2a0

EXAMPLE

package main
import (
&quot;bufio&quot;
&quot;bytes&quot;
&quot;fmt&quot;
&quot;net&quot;
&quot;strings&quot;
&quot;time&quot;
)
var RouteMap = make(map[PathIdentifier]Controller)
func main() {
ln, err := net.Listen(&quot;tcp&quot;, &quot;:8080&quot;)
if err != nil {
// handle error
}
MapRoute(&quot;/&quot;, HomeController)
MapRoute(&quot;categories&quot;, CategoriesController)
MapRoute(&quot;categories/{category}&quot;, CategoryController)
MapRoute(&quot;categories/{category}/{product}&quot;, CategoryProductController)
MapRoute(&quot;basket&quot;, BasketController)
MapRoute(&quot;checkout&quot;, CheckoutController)
MapRoute(&quot;sitemap&quot;, SitemapController)
MapRoute(&quot;contact&quot;, ContactController)
MapRoute(&quot;services/order&quot;, OrderServiceController)
MapRoute(&quot;services/basket&quot;, BasketServiceController)
MapRoute(&quot;services/image&quot;, ImageServiceController)
fmt.Printf(&quot;%s\n&quot;, RouteMap)
for {
conn, err := ln.Accept()
if err != nil {
// handle error
}
go RequestHandler(conn)
}
}
// ----------------------- Request &amp; Response ---------------------------
func ParseQueryString() {}
func ParsePostData() {}
func ResponseHeaders() {}
func ParseRequestHeaders() {}
func RequestHandler(conn net.Conn) {
CrLf := &quot;\r\n&quot;
Terminator := CrLf + CrLf
defer func() {
//fmt.Println(&quot;Closing connection...&quot;)
conn.Close()
}()
timeoutDuration := 10 * time.Second
bufReader := bufio.NewReader(conn)
conn.SetReadDeadline(time.Now().Add(timeoutDuration))
requestBytes, err := bufReader.ReadBytes(&#39;\n&#39;)
if err != nil {
fmt.Println(err)
return
}
requestTokens := bytes.Split(requestBytes, []byte(&quot; &quot;))
requestMethod := string(requestTokens[0])
requestPath := string(requestTokens[1])
//requestHTTPVersion := string(requestTokens[2])
if requestMethod == &quot;GET&quot; {
// Parse path
pathTokens := strings.Split(requestPath, &quot;/&quot;)
segments := len(pathTokens)
key := PathIdentifier{path: &quot;categories/{category}/{product}&quot;, segments: (segments - 1)}
c := RouteMap[key]
fmt.Print(&quot;%s\n&quot;, c)
}
document := []byte(&quot;HTTP/1.1 200 OK&quot; + CrLf + &quot;Date: Mon, 27 Jul 2009 12:28:53 GMT&quot; + CrLf + &quot;Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT&quot; + CrLf + &quot;Content-Length: 49&quot; + CrLf + &quot;Content-Type: text/html&quot; + CrLf + &quot;Connection: Closed&quot; + Terminator + &quot;&lt;html&gt;&lt;body&gt;&lt;h1&gt;Hello, World!&lt;/h1&gt;&lt;/body&gt;&lt;/html&gt;&quot; + Terminator)
conn.Write(document)
}
// ----------------------------- Controller -----------------------------
type Controller func()
type PathIdentifier struct {
path     string
segments int
}
func MapRoute(view string, controller Controller) {
if controller != nil {
if view != &quot;/&quot; {
pathTokens := strings.Split(view, &quot;/&quot;)
key := PathIdentifier{path: view, segments: len(pathTokens)}
RouteMap[key] = controller
return
}
key := PathIdentifier{path: view, segments: 1}
RouteMap[key] = controller
}
}
func HomeController() {
fmt.Print(&quot;Invoking the HomeController.\n&quot;)
}
func OrderServiceController() {
}
func BasketServiceController() {
}
func CategoriesController() {
}
func CategoryController() {
}
func CategoryProductsController() {
}
func CategoryProductController() {
}
func BasketController() {
}
func ImageServiceController() {
}
func SitemapController() {
}
func CheckoutController() {
}
func ContactController() {
}

答案1

得分: 1

我不确定你需要称之为“按地址调用”。当你通过将其作为变量传递来调用时,编译器会在幕后为你完成这个操作。它会获取其地址并调用它。

如果你希望有一定程度的间接性,你可以这样做:

M := map[string]func()
M["function 1"] = F
// 然后可以通过 map 来调用它们
M["function 1"]()
英文:

I'm not sure you need to call it "by address". When you call by passing it as a variable, compiler does this for you "under-the-hood". Takes its address and calls it.

If you wish some level of indirection, you can make:

M := map[string]func()
M[&quot;function 1&quot;] = F
// and then call them from map like 
M[&quot;function 1&quot;]()

huangapple
  • 本文由 发表于 2017年4月12日 00:48:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/43351857.html
匿名

发表评论

匿名网友

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

确定