Re: Convert an interface{} argument back to its original type

606 views
Skip to first unread message

Robert Carlsen

unread,
Sep 21, 2012, 9:42:17 AM9/21/12
to golan...@googlegroups.com

func myprint(args ...interface{}) {
for _, arg := range args {
switch v := reflect.ValueOf(arg); v.Kind() {
case reflect.String:
os.Stdout.WriteString(v.String())
case reflect.Int:
os.Stdout.WriteString(strconv.FormatInt(v.Int(), 10))
case reflect.Struct:
os.Stdout.WriteString(struct_printer(arg.(WHAT GOES HERE))) // I don't want to use the something struct specifically

Since struct_printer takes a Stringer (interface type) - you could just type assert arg to a stringer:

os.Stdout.WriteString(struct_printer(arg.(Stringer))).

There isn't any way to retrieve the struct val typed as its original struct type (other than reflect) without type asserting back to "something" explicitly.  But this is where interfaces come to save the day.  If I were you, I would: (untested code)

func myprint(args ...interface{}) {
for _, arg := range args {
if s, ok := arg.(Stringer); ok {
os.Stdout.WriteString(s.String())
}
switch v := reflect.ValueOf(arg); v.Kind() {
case reflect.String:
os.Stdout.WriteString(v.String())
case reflect.Int:
os.Stdout.WriteString(strconv.FormatInt(v.Int(), 10))
case reflect.Struct:
// doing this "properly" for not a stringer requires more heavy use of the reflect pkg
}
}
}

Robert Carlsen

unread,
Sep 21, 2012, 9:44:57 AM9/21/12
to golan...@googlegroups.com
Edit - 


func myprint(args ...interface{}) {
for _, arg := range args {
if s, ok := arg.(Stringer); ok {
os.Stdout.WriteString(s.String())
  continue
}
switch v := reflect.ValueOf(arg); v.Kind() {
case reflect.String:
os.Stdout.WriteString(v.String())
case reflect.Int:
os.Stdout.WriteString(strconv.FormatInt(v.Int(), 10))
case reflect.Struct:
// doing this "properly" for not a stringer requires more heavy use of the reflect pkg
}
}
}

A type switch could be helpful too. 

Rory McGuire

unread,
Sep 21, 2012, 2:54:22 PM9/21/12
to golan...@googlegroups.com


On Friday, 21 September 2012 15:42:18 UTC+2, Robert Carlsen wrote:
...
os.Stdout.WriteString(struct_printer(arg.(Stringer))).

Awesome. Thanks that is what I was missing.
So you can specialize the interface{} to the interface you are wanting to use.

Rory McGuire

unread,
Sep 21, 2012, 3:09:18 PM9/21/12
to golan...@googlegroups.com

On Friday, 21 September 2012 15:44:57 UTC+2, Robert Carlsen wrote:

A type switch could be helpful too. 

Thanks, no more reflect. :D funny because the video is promoting the reflect capabilities but Russ also says one should avoid it if possible.

Final (How to choose the interface to use an interface{} as):
package main

import (
"os"
"strconv"
)

type something struct {
woot string
}

func (s something) String() string {
return "used something.String()" + s.woot
}

func main() {
myprint2("Hello", 42, something{"wowee"}, "\n")
}

func myprint2(args ...interface{}) {
for _, arg := range args {
if _, ok := arg.(Stringer); ok {
os.Stdout.WriteString(arg.(Stringer).String())
continue
}
switch arg.(type) {
case int:
os.Stdout.WriteString(strconv.FormatInt(int64(arg.(int)), 10))
case string:
os.Stdout.WriteString(arg.(string))
default:
panic("Unhandled type")
}
}
}

type Stringer interface {
String() string
}
 

Just for searching later; error was:
./myprint.go:36: cannot use arg (type interface {}) as type Stringer in function argument:
interface {} does not implement Stringer (missing String method)

Rémy Oudompheng

unread,
Sep 21, 2012, 3:23:11 PM9/21/12
to Rory McGuire, golan...@googlegroups.com
You can use the "switch v := arg.(type)" form to avoid doing a type
assertion in each case (in this form, v will have the corresponding
type in each case).

You can also put Stringer as a case in the type switch for less
verbosity. Note that you could use the first result of arg.(Stringer)
instead of discarding it. It avoid repeating arg.(Stringer) twice.

switch x := arg.(type) {
case Stringer:
os.Stdout.WriteString(x.String())
case int:
os.Stdout.WriteString(strconv.FormatInt(int64(x), 10))
case string:
os.Stdout.WriteString(arg)
default:
panic("Unhandled type")
}

Rémy.

Rory McGuire

unread,
Sep 21, 2012, 4:18:36 PM9/21/12
to Rémy Oudompheng, golan...@googlegroups.com
Nice. Thanks for the tip.
Reply all
Reply to author
Forward
0 new messages