routing web.go

48 views
Skip to first unread message

m

unread,
Aug 2, 2010, 5:55:55 PM8/2/10
to golang-nuts
web.go has a simple formula for routing. For example get requests:

web.Get("/(.*)", hello)

What I want is to dynamically set the function that is routed too.
That way I can have a .go file for each of my pages, then iterate over
something (either a directory scan or a JSON file, whatever) and
create new routers. For example:

for i := 0; i < len(somearray); i++ {
web.Get("/" + somearray[i], somearray[i] + "Get")
}

Or something similar. However, web.Get() doesn't take strings in the
second argument. What is the way to properly do this?

Andrew Gerrand

unread,
Aug 3, 2010, 12:02:33 AM8/3/10
to m, golang-nuts
Go's http package offers very similar functionality to web.go, and
will let you defined your own Handler can do what you describe.
Implement an http.Handler which performs the relevant routing, and
pass it to http.ListenAndServe:
http://golang.org/pkg/http/#ListenAndServe

There is a thoroughly explained example of using the http package here:
http://golang.org/doc/codelab/wiki/

Andrew

m

unread,
Aug 3, 2010, 1:05:46 AM8/3/10
to golang-nuts
Thanks, but this code doesn't seem to allow dynamic function calling,
which is necessary for routing an n number of pages with their own
logic.

On Aug 3, 12:02 am, Andrew Gerrand <a...@golang.org> wrote:
> Go's http package offers very similar functionality to web.go, and
> will let you defined your own Handler can do what you describe.
> Implement an http.Handler which performs the relevant routing, and
> pass it to http.ListenAndServe:
>  http://golang.org/pkg/http/#ListenAndServe
>
> There is a thoroughly explained example of using the http package here:
>  http://golang.org/doc/codelab/wiki/
>
> Andrew
>

Cory Mainwaring

unread,
Aug 3, 2010, 1:17:32 AM8/3/10
to m, golang-nuts
If all of the functions have the same signature, then you can use a function map to do it in an expected way:

func main() {
m := make(map[string]func()int)
m["getTen"] = func()int {
return 10
}
m["getFive"] = func()int {
return 5
}
ten := "Ten"
println(m["get" + ten]())
println(m["getFive"]())
}

You can also use a slice of function pointers, or just individual function pointers if you want to, but as you can see in the above, strings can be concatenated to make your calling very easy, though you can probably remove all of the "get"s and just use the names, or numbers if you use a function array. Depending on your implementation details, this could be the right path for you.

m

unread,
Aug 3, 2010, 1:27:22 AM8/3/10
to golang-nuts
Thanks Corey. You're still explicitly invoking from code though.. I
guess the heart of my question was whether you can invoked a function
call with a string of the function name. Maybe you can't.

On Aug 3, 1:17 am, Cory Mainwaring <olre...@gmail.com> wrote:
> If all of the functions have the same signature, then you can use a function
> map to do it in an expected way:
>
> func main() {
> m := make(map[string]func()int)
> m["getTen"] = func()int {
> return 10}
>
> m["getFive"] = func()int {
> return 5}
>
> ten := "Ten"
> println(m["get" + ten]())
> println(m["getFive"]())
>
> }
>
> You can also use a slice of function pointers, or just individual function
> pointers if you want to, but as you can see in the above, strings can be
> concatenated to make your calling very easy, though you can probably remove
> all of the "get"s and just use the names, or numbers if you use a function
> array. Depending on your implementation details, this could be the right
> path for you.
>

Cory Mainwaring

unread,
Aug 3, 2010, 1:33:43 AM8/3/10
to m, golang-nuts
As far as I know, you cannot invoke a function with a string in Go. I don't think you can do this in C either without a construct such as a hash map being a buffer. If it can be done directly in C, Go will likely support something similar. As far as a single package goes, you can have all of the functions be callable by string by adding the function pointers to a hash-map that's declared at the top level. This can be emulated with other packages as well via:

var map map[string]func()int
map["name"] = func()int {}

func Hash(name string) func()int {
    return map[name]
}

Then you just do a pkg_name.Hash("function") to get a pointer to it. Andrew, Ian, Rob, or Russ will be able to shed more light on the possibilities of functions being called by string.

Russ Cox

unread,
Aug 3, 2010, 1:38:03 AM8/3/10
to m, golang-nuts
You can't look up a function by string at run time.
Among other complications, that would prevent the
linker from throwing away apparently unused code.
This is, after all, a compiled language.

The only choice is to build an explicit map from string
to function handler and then iterate over it, or something
similar. With a short script, you could generate that
code as part of your build process instead of maintaining
it by hand.

Russ

m

unread,
Aug 3, 2010, 1:55:16 AM8/3/10
to golang-nuts
I'm not understanding how this works. what does func()int mean? why
int? Here is the example that I threw together, which fails. Please
correct:


package main

import (
"fmt"
)

func main() {
var map map[string]func()int
map["name"] = name()

Hash("name")
}

func Hash(name string) func()int {
return map[name]
}

func name() {
fmt.Println("It worked!")

Cory Mainwaring

unread,
Aug 3, 2010, 2:46:34 AM8/3/10
to m, golang-nuts
Disclaimer: I'm going to call them function signatures, but they could be called "function types", "function definitions" or various other things. Signatures seem the most appropriate to me.

A function's signature is the basic representation of it's input and output. In Go, the most basic function signature is "func()". This signature refers to a function that takes no arguments and returns no values.

A more verbose way of declaring a function signature is "func()()". The first set of parentheses is the arguments that it takes, and the second set of parentheses contains the types that the function returns.

A more common signature would be "func(int)int" which is the signature of a function that takes a single integer and returns a single integer.

As you'll have noticed, there are no names in a function signature. This is because it's just refering to what kind of data is inputted and what kind of data is outputted, thus everything else, like names is irrelevant.

Notes on Syntax:
When there is only one returned value for a function, you can skip the parentheses around it.
You can never skip the parentheses around the arguments.
"func" is the keyword for the beginning of a function signature.


On the pieces of your code that didn't work:
"map" is a keyword and cannot be used as a variable.
You must use make() to initialize your map. In your code: "var funcMap map[string]func()int = make(map[string]func()int)"
When assigning a value to a function map, you need to make sure you are assigning the function and not the return value of the function: "funcMap["name"] = name"
Hash returns a function, not the output of a function. So, Hash("name") doesn't execute Hash("name"), just puts it in place, you need to include parentheses after that for it to run it: "Hash("name")()"
Your map's function signature does not match the function signature of "name". In Go, they must match, or else it's like taking the value of an int variable and assigning it to a float variable. In this case, I think you would have preferred changed the function signature in the map: "var funcMap map[string]func() = make(map[string]func())"
In regards to the last point, make sure that "Hash" returns the same function signature as your map, or else Go will see a type error: "func Hash(name string) func() {"
The map must be defined outside of "main" if you want Hash to be able to see it.

I've attached commented code that will hopefully help to see what's actually going on with the hash map of functions.

Hope this helps,

Cory
funcmap.go

Daniel Barrett

unread,
Aug 3, 2010, 2:59:15 AM8/3/10
to m, golang-nuts
On Mon, 2010-08-02 at 22:55 -0700, m wrote:
> I'm not understanding how this works. what does func()int mean? why
> int?

"func() int" is the type of functions which take no arguments and which
return an int. As another example I'll use a "func(string, string)
string" in the following code.

package main

import (
"fmt"
)

type Fn func(string, string) string

func secondThenFirst(first, second string) string {
return fmt.Sprintf("%s %s", second, first)
}

func main() {
var f Fn = secondThenFirst

fmt.Printf(f("world\n", "hello"))
}

---


> Here is the example that I threw together, which fails. Please
> correct:

<< snip >>

Hopefully this is illustrative for you:

package main

import (
"fmt"
)

type Fn func()
type FnMap map[string] Fn

func test0() {
fmt.Printf("called test0\n")
}

func test1() {
fmt.Printf("called test1\n")
}

func main() {
fns := make( FnMap )
fns["test0"] = test0
fns["test1"] = test1

fns["test1"]()
fns["test0"]()
}


Michael Hoisie

unread,
Aug 3, 2010, 3:41:32 AM8/3/10
to golang-nuts
If you have an instance of a type with methods, you can call those
methods dynamically with the reflect package. There's an example here
(see 'callMethod', this is originally from pkg/template):
http://github.com/hoisie/mustache.go/blob/master/mustache.go

This won't allow you to call functions at the package level though..

Mike

roger peppe

unread,
Aug 3, 2010, 5:28:11 AM8/3/10
to m, golang-nuts

one way to do this kind of thing is to have a central
registry of functions and have each module call a Register
function at init time.

for instance:

// main.go
package main
var handlers = make(map[string]interface{})

func RegisterHandler(s string, h interface{}){
handlers[s] = h
}

// page1.go
package main
func init() {
RegisterHandler("page1", page1handler)
}
func page1handler(s string){
}

// someotherpage.go
....
for i := 0; i < 10; i++ {
s := fmt.Sprintf("page%d", i)
web.Get("/" + s, handlers[s])
}


hope this helps.

PS FWIW, i don't think i'm keen on the way that web.go uses dynamically
typed handlers. i like to see what kind of function is expected as an argument;
i don't think it would be too hard to do.

Reply all
Reply to author
Forward
0 new messages