打印一个Go类型,忽略”String() string”方法。

huangapple go评论86阅读模式
英文:

Printing a Go type ignoring "String() string" method

问题

如果我在Go语言中有一个类型定义如下:

type myType ...

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

我如何使用默认表示(即不调用String()方法)来打印该类型(使用各种fmt函数)?我想要做的是像这样:

func (m myType) String() string {
    // 一些任意的属性
    if myType.isValid() {
        // 格式化正确
    } else {
        // 会无限递归;希望使用默认表示
        return fmt.Sprintf("无效的myType:%v", m)
    }
}
英文:

If I have a type in go like this:

type myType ...

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

how can I print (using the various fmt functions) this type using the default representation (that is, instead of having String() called)? What I'd like to do is something like this:

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)
    }
}

答案1

得分: 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))
}
英文:

fmt.Stringer is the default format, which is called when you use %v. If you want the Go syntax, use %#v.

Alternatively, you can bypass the reflection in fmt altogether, and format your output as you see fit.

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

If the underlying type of myType is a number, string or other simple type, then convert to the underlying type when printing:

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

答案2

得分: 4

使用%#v代替%v

这样不会调用String()方法,但如果你实现了GoString()方法,它会调用GoString()方法。

英文:

Use %#v instead of %v

That will not invoke String(). - but it will invoke GoString() if you implement it.

答案3

得分: 2

使用%#v格式是不正确的答案,如果你想要让底层类型的String方法工作,或者你的类型是一个类型别名。

Effective Go中所解释的,只需将其转换回表示的类型即可:

type Foo int

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

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

Playground

**编辑:**正如其他人在评论中指出的,如果你的类型是一个结构体,除了将其转换为具有相同字段的匿名结构体类型,使用%#v格式似乎是唯一的方法。

英文:

Using %#v format is not the correct answer if you want to get your underlying type's String to work or your type is a type alias.

As is explained in Effective Go, just convert it back to the type it represents:

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.

EDIT: As others have pointed out in the comments, if your type is a struct, using %#v format seems like the only way besides converting it to an anonymous struct type with same fields.

huangapple
  • 本文由 发表于 2014年9月24日 22:29:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/26019503.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定