template formatting of pointer fields

2,145 views
Skip to first unread message

Kyle Consalus

unread,
Jan 24, 2011, 2:37:10 PM1/24/11
to golang-nuts
If I had a structure that I don't own and has pointer members (such as the stucts generated by the goprotobuf), what is the
best way to display the field values?

Example:

import (
"os"
"template"
)

type Person struct {
Name *string
Age  *int
}

var tpl = template.MustParse("{Name}: {Age}\n", nil)

func main() {
name := "Oliver"
age := 37
p := &Person{&name, &age}
tpl.Execute(p, os.Stdout)
}

This outputs "0x389230: 0x3410f8". Not what I want, but not entirely surprising. It is printing the pointers, just like I asked.
I tried a variety of things, but nothing aside from making my own dereferencing formatter resulted in the actual value being shown.
I can't (and don't really want to) add "GetName/GetAge", since the struct in real life is from another package. I could wrap it, but
I'd have to wrap the entire tree. So, using a custom formatter does the job, but since formatters can't be chained (yet?) it means I need to manually
set up the escaping I want.

Is there a better way?

ziutek

unread,
Jan 24, 2011, 5:42:43 PM1/24/11
to golang-nuts
Go templates doesn't automatically dereferences pointers. But you may
specify your own formatter witch dereference values:

Simple and dirty example:

fmap = template.FormatterMap{
"deref": func(wr io.Writer, fm string, data ...interface{}) {
for _, dd := range data {
switch vv := dd.(type) {
case *string:
fmt.Fprint(wr, *vv)
case *int:
fmt.Fprint(wr, *vv)
default:
fmt.Fprint(wr, vv)
}
}
},
}
tpl = template.MustParse("{Name|deref}: {Age|deref}\n", fmap)

Have you ever tried Kasia.go? It automatically dereferences pointers.
Below your example written with Kasia.go template:

package main

import (
"os"
"kasia"
)

type Person struct {
Name *string
Age *int
}

func main() {
tpl, _ := kasia.Parse("$Name: $Age\n")

name := "Oliver"
age := 37
p := &Person{&name, &age}
tpl.Execute(p, os.Stdout)
}

Visit https://github.com/ziutek/kasia.go for more information.

Steven

unread,
Jan 24, 2011, 5:45:51 PM1/24/11
to Kyle Consalus, golang-nuts
On Monday, January 24, 2011, Kyle Consalus <cons...@gmail.com> wrote:
> If I had a structure that I don't own and has pointer members (such as the stucts generated by the goprotobuf), what is thebest way to display the field values?

> Example:
>
> import ( "os" "template")
> type Person struct { Name *string Age  *int}
> var tpl = template.MustParse("{Name}: {Age}\n", nil)
> func main() { name := "Oliver"
> age := 37 p := &Person{&name, &age} tpl.Execute(p, os.Stdout)
> }
> This outputs "0x389230: 0x3410f8". Not what I want, but not entirely surprising. It is printing the pointers, just like I asked.I tried a variety of things, but nothing aside from making my own dereferencing formatter resulted in the actual value being shown.
> I can't (and don't really want to) add "GetName/GetAge", since the struct in real life is from another package. I could wrap it, butI'd have to wrap the entire tree. So, using a custom formatter does the job, but since formatters can't be chained (yet?) it means I need to manually

> set up the escaping I want.
> Is there a better way?
>

Yeah, only way I could think of was using an indirection formatter,
which is what you were trying to avoid:
http://goo.gl/W41zk

Chaining shouldn't be too bad though. Just put your FormatterMap in a
variable. Store your indirectFormatter by multiple names, like
indirect_format for any given format. Then the indirectFormatter just
has to strip the first 9 bytes from the string (formatter[9:]), and
pass along the arguments to the right formatter.

I do think this should be better addressed in the library, though,
unless there's something I'm missing..

ziutek

unread,
Jan 24, 2011, 5:53:08 PM1/24/11
to golang-nuts
> So, using a custom formatter does the job,
> but since formatters can't be chained (yet?) it means I need to manually
> set up the escaping I want.

Somehow I missed that...

For HTML escaping you may write even more dirty formatter:

func(wr io.Writer, fm string, data ...interface{}) {
for _, dd := range data {
switch vv := dd.(type) {
case *string:
template.HTMLEscape(wr, []byte(fmt.Sprint(*vv)))
case *int:
template.HTMLEscape(wr, []byte(fmt.Sprint(*vv)))
default:
template.HTMLEscape(wr, []byte(fmt.Sprint(vv)))
}
}
}

ziutek

unread,
Jan 24, 2011, 6:15:39 PM1/24/11
to golang-nuts
> http://goo.gl/W41zk

What a beautiful formatter! Please forget about my dirty examples :)
Reply all
Reply to author
Forward
0 new messages