Go 中的 ToString()函数

strings.Join函数只接受字符串的片段:

s := []string{"foo", "bar", "baz"}
fmt.Println(strings.Join(s, ", "))

但是如果能够传递实现 ToString()函数的任意对象就更好了。

type ToStringConverter interface {
ToString() string
}

在 Go 中是否有类似的东西,还是我必须用 ToString 方法装饰现有类型(如 int) ,并在 strings.Join周围编写一个包装器?

func Join(a []ToStringConverter, sep string) string
155064 次浏览

String() string方法附加到任何命名类型,并享受任何自定义的“ ToString”功能:

package main


import "fmt"


type bin int


func (b bin) String() string {
return fmt.Sprintf("%b", b)
}


func main() {
fmt.Println(bin(42))
}

操场: http://play.golang.org/p/Azql7_pDAA


输出

101010

我比较喜欢这样的:

type StringRef []byte


func (s StringRef) String() string {
return string(s[:])
}


…


// rather silly example, but ...
fmt.Printf("foo=%s\n",StringRef("bar"))

当你有自己的 struct,你可以有自己的 转换成字符串转换成字符串功能。

package main


import (
"fmt"
)


type Color struct {
Red   int `json:"red"`
Green int `json:"green"`
Blue  int `json:"blue"`
}


func (c Color) String() string {
return fmt.Sprintf("[%d, %d, %d]", c.Red, c.Green, c.Blue)
}


func main() {
c := Color{Red: 123, Green: 11, Blue: 34}
fmt.Println(c) //[123, 11, 34]
}

另一个结构的例子:

package types


import "fmt"


type MyType struct {
Id   int
Name string
}


func (t MyType) String() string {
return fmt.Sprintf(
"[%d : %s]",
t.Id,
t.Name)
}

用的时候要小心,
与’+’ 连接不能编译:

t := types.MyType{ 12, "Blabla" }


fmt.Println(t) // OK
fmt.Printf("t : %s \n", t) // OK
//fmt.Println("t : " + t) // Compiler error !!!
fmt.Println("t : " + t.String()) // OK if calling the function explicitly

这里有一个简单的方法来处理这个问题:

package main


import (
"fat"
"strconv"
)


type Person struct {
firstName, lastName string
age int
}


func (p Person) GetFullName() string {
return p.firstName + " " + p.lastName
}


func (p Person) GetAge() int {
return p.age
}


func (p Person) GetAgeAsString() string {
return strconv.Itoa(p.age)
}


func main() {
p := Person {"John", "Doe", 21}
fmt.Println(p.GetFullName())
fmt.Println(p.GetAgeAsString())
}

产出:

"John Doe"
"21"
  • 效果不错
   package main
    

import "fmt"
    

    

type Person struct {
fname, sname string
address string
}
    

    

func (p *Person) String() string {
s:=  fmt.Sprintf("\n %s %s  lives at %s \n", p.fname, p.sname, p.address)
return s
}
    

    

func main(){
alex := &Person{"Alex", "Smith", "33 McArthur Bvd"}
fmt.Println(alex)
    

}


产出:

Alex Smith 住在 McArthur Bvd 33号

如果你有一组固定的可以转换的元素类型,那么你可以为每个元素定义转换函数,以及一个通用的转换函数,它使用反射来测试一个元素的实际类型,并调用该元素的相关函数,例如:

func ToStringint(x int) string {
return strconv.Itoa(x)
}


func ToStringlong(x int64) string {
return strconv.FormatInt(x,10)
}


func ToStringdouble(x float64) string {
return fmt.Sprintf("%f", x)
}


func ToStringboolean(x bool) string {
if x {
return "true"
}
return "false"
}


func ToStringOclAny(x interface{}) string {
if reflect.TypeOf(x) == TYPEint {
return strconv.Itoa(x.(int))
}


if reflect.TypeOf(x) == TYPEdouble {
return fmt.Sprintf("%f", x.(float64))
}


if reflect.TypeOf(x) == TYPElong {
return strconv.FormatInt(x.(int64),10)
}


if reflect.TypeOf(x) == TYPEString {
return x.(string)
}


if reflect.TypeOf(x) == TYPEboolean {
return ToStringboolean(x.(bool))
}


if reflect.TypeOf(x) == TYPESequence {
return ToStringSequence(x.(*list.List))
}


if reflect.TypeOf(x) == TYPEMap {
return ToStringMap(x.(map[interface{}]interface{}))
}


return ""
}


func ToStringSequence(col *list.List) string {
res := "Sequence{"
for e := col.Front(); e != nil; e = e.Next() {
res = res + ToStringOclAny(e.Value)
if e.Next() != nil {
res = res + ", "
}
}
return res + "}"
}


func ToStringSet(col *list.List) string {
res := "Set{"
for e := col.Front(); e != nil; e = e.Next() {
res = res + ToStringOclAny(e.Value)
if e.Next() != nil {
res = res + ", "
}
}
return res + "}"
}


func ToStringMap(m map[interface{}]interface{}) string {
res := "Map{"
for i, v := range m {
res = res + ToStringOclAny(i) + " |-> " + ToStringOclAny(v) + " "
}
return res + "}"
}