Type assertion (interface{} to slice) or expanding slices in templates

7,639 views
Skip to first unread message

Paddy Foran

unread,
Nov 20, 2011, 6:47:48 AM11/20/11
to golan...@googlegroups.com
Hello,

I've been playing with template functions in Go weekly's text/template library. They've solved a lot of my problems, but they keep raising new problems. For example, I'm trying to pass a slice of values ([]*T) to a template function (func(args interface{}) string). If I don't make args an interface{}, I get a runtime error. However, I can't loop over an interface{}. I try to use type assertion (a, err := args.([]T) or args.([]*T)), and it gives me an empty slice, even though I can verify args previously held values. I know I can use args ...interface{}, but I can't seem to find a way to expand the slice in the template to pass its members as arguments.

Any thoughts on how I can pass a slice from a template to a template function?

Thanks,
Paddy Foran

Rob 'Commander' Pike

unread,
Nov 20, 2011, 3:49:22 PM11/20/11
to Paddy Foran, golan...@googlegroups.com

Show your code. I don't understand what you're saying. I suspect the root problem has nothing to do with templates.

-rob


Paddy Foran

unread,
Nov 20, 2011, 4:20:45 PM11/20/11
to Rob 'Commander' Pike, golan...@googlegroups.com
Hi Rob,

The function is intended to compare two Device objects, based on their Address field.

What's in the Template Function

func deviceSelected(device string, devices interface{}) bool {
    if device == "" {
        panic("Need device")
    }
    if devices == nil {
        panic("Need devices")
    }
    vices, err := devices.([]interface{})
    if err {
        panic("type conversion failed")
    }
    log.Print(vices)
    for _, d := range vices {
        y, err := d.(Device)
        if err {
            panic("Type conversion failed.")
        }
        log.Printf("%s == %s", device, y.Address)
        if device == y.Address {
            return true
        }
    }
    return false
}

What Is In The Template

{{ range $.User.Devices }}<li data-address="{{ .Address }}"{{ if deviceSelected .Address $.Links.Devices }} class="primary"{{ end }}>{{ .Name }}</li>{{ end }}

What Is Being Printed in the Logs

[] <---- empty slice from log.Print(vices)

What Is Being Passed In

[0x1193bde0] <-- slice containing a single *Device

What I've tried:
  • Tried making the devices argument a []interface{} type. At runtime, I got a complaint that the function expected []interface{} and got interface{}
  • Tried looping over interface. Interfaces can't be looped over.
  • Tried using type assertion to turn the devices argument into []interface{} type (above)
  • Tried using type assertion to turn the devices argument into []*Device
Hope I provided enough/the right information. I'm sure I'm doing something dumb, but I just can't figure out what it is for the life of me. Would love any insight.

Thanks,
Paddy Foran
Message has been deleted

Paddy Foran

unread,
Nov 20, 2011, 5:27:44 PM11/20/11
to golan...@googlegroups.com, Rob 'Commander' Pike
I had tried making that change, but it threw a panic. I added a log.Printf("%T", devices) before the panic, and got wonderfully bizarre news: The type is []*main.Device. Which seems right. So.. why is it panicking? (Before anyone asks, vices also reports being a []*main.Device type, according to Printf("%T")). I tested with passing in ints and trying to convert them to ints, and the same thing happened. I'm on the weekly build, if that makes a difference.

It looks like I'm getting erroneous type assertion errors. Is this me being dumb or me getting errors where I'm not supposed to?

Thanks,
Paddy Foran


On Sun, Nov 20, 2011 at 5:16 PM, Gus Soden <augus...@rocketmail.com> wrote:
I added comments to one fragment of code to explain what I think is going on:

    vices, err := devices.([]interface{})  // evaluates to nil, false because devices is type []*Device
    if err {
        // never get here because err is false

        panic("type conversion failed")
    }
    log.Print(vices)  // nil slices print as "[]"




Message has been deleted

Paddy Foran

unread,
Nov 20, 2011, 6:10:10 PM11/20/11
to golan...@googlegroups.com, Rob 'Commander' Pike
That got it working perfectly. Thanks! Can't believe I screwed that up. I've been wrestling with this all day. Funnily enough, I actually read the spec's type assertion docs several times, and still couldn't figure this out.

Thanks for all the assistance!

Thanks,
Paddy Foran


On Sun, Nov 20, 2011 at 5:59 PM, Gus Soden <augus...@rocketmail.com> wrote:
One thing that might be causing confusion is that the second result of a type assertion is a boolean, not an error.  The boolean is true if the assertion holds.  This fragment of code panics when devices is of type []interface. 

    vices, err := devices.([]interface{})
    if err {

        panic("type conversion failed")
    }

The code will be clearer if you s/err/ok/,

Reply all
Reply to author
Forward
0 new messages