2014-09-24 142 views
3

如果我有这样的旅途中类型:打印围棋类型忽略“字符串()字符串”方法

type myType ... 

func (m myType) String() string { ... } 

我怎么能打印(使用各种fmt功能)这类使用默认的表示(那就是,而不是叫String())?我想要做的是这样的:

func (m myType) String() string { 
    // some arbitrary property 
    if myType.isValid() { 
     // format properly 
    } else { 
     // will recurse infinitely; would like default 
     // representation instead 
     return fmt.Sprintf("invalid myType: %v", m) 
    } 
} 

回答

3

使用%#v而不是%v

这不会调用字符串()。 - 但它会调用GoString(),如果你实现它。

+0

这是Effective Go中的内容。 OP应该将该值转换为基础类型,然后使用'%v'格式。看到我的答案。 – 2014-09-24 14:52:01

+1

@ Ainar-G对于类型别名,您的答案很简单,但对于例如'输入myType struct {myOtherType}'。 Effective Go中似乎也没有任何内容表明%#v不是OP想要的。 – nos 2014-09-24 15:09:24

+0

你是对的,编辑我的答案。 – 2014-09-24 15:18:11

6

fmt.Stringer默认格式,当您使用%v时会调用该格式。如果您需要Go语法,请使用%#v

或者,您可以完全绕过fmt中的反射,并按照您认为合适的方式格式化输出。

func (m myType) String() string { 
    return fmt.Sprintf("{Field: %s}", m.Value) 
} 

如果基础类型的myType的是一个数字,字符串或其它简单的类型,然后在打印时转换为基本类型:

func (m mType) String() string { 
    return fmt.Sprint(int(m)) 
} 
2

使用%#v格式不正确的答案,如果你想让您的基础类型的String工作或您的类型是一个类型别名。

正如在Effective Go解释,只是将其转换回它所代表的类型:

type Foo int 

func (f Foo) String() string { 
    if f == 0 { 
     return "foo" 
    } 
    return fmt.Sprintf("%v", int(f)) // N.B. 
} 

func main() { 
    fmt.Println(Foo(0)) 
    fmt.Println(Foo(42)) 
} 

Playground

编辑:正如其他人在评论中所指出的那样,如果你的类型是一个结构,使用%#v格式好像除了将其转换为匿名结构类型与同一领域的唯一途径。

+0

只有'myType'是一个类型别名,这才真正有帮助。更频繁的是它本身就是一个结构。 – JimB 2014-09-24 14:59:02

+0

有没有办法做到这一点,不涉及显式转换?我的用例是我有一个结构,创建它的匿名版本只是为了打印,然后在两者之间进行转换会很痛苦。 – joshlf 2014-09-24 15:01:52

+0

@JimB,synful你是对的。我会编辑我的答案。 – 2014-09-24 15:13:33