如何将用户定义的命名类型/结构转换为其匿名类型?

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

How to convert a user-defined named type/struct to it's anonymous type

问题

原始问题

我有以下的Go代码。我想要处理`Foo`结构体或`Bar`类型作为字符串。通过“处理”,我指的是将其底层值转换/强制转换/等等为(真实的)类型`string`。我有一个解决方法,但对于结构体来说,我觉得它不直观。

选择类型(而不是结构体)似乎是更好的方法。我不需要维护任何状态,也不需要“继承”类型特定的功能,所以在我的情况下应该可以工作。然而,调用type.String()会导致堆栈递归。我主要是想知道我是否遗漏了什么(显而易见的东西)。

package main

import "fmt"

type Foo struct {
    string
}

func (f *Foo) String() string {
    return f.string
}


type Bar string

func (b *Bar) String() string {
    return fmt.Sprintf("%s", b) // 不能使用:return string(b) 这里。
}

func main() {
    a := Foo{"a"}
    var b Bar
    b = "b"

    fmt.Printf("A is: %s\n", a) // 不调用a.String()?
    //fmt.Printf("A is: %s\n", string(a)) // 不起作用
    fmt.Printf("A is: %s\n", a.string)   // workaround A
    fmt.Printf("A is: %s\n", a.String()) // workaround B, required if I want to use it in a different package

    fmt.Printf("B is: %s\n", b) // 调用b.String()
    fmt.Printf("B is: %s\n", string(b))
    //fmt.Printf("B is: %s\n", b.String()) // 导致堆栈溢出
}

输出:

A is: {a}
A is: a
A is: a
B is: b
B is: b

Go Playground上的代码:https://play.golang.org/p/zgrKao4cxa
这种行为是Go版本1.5.2的。

回答

以下是基于我原始问题的答案的简短示例。此外,以下帖子有助于理解和推理这个主题:https://stackoverflow.com/questions/27775376/value-receiver-vs-pointer-receiver-in-golang

对于类型,以下代码可以工作:

type MyString string

func (b MyString) String() string {
    return string(b)
}

Go Playground链接:https://play.golang.org/p/H12bteAk8D

对于结构体,以下代码可以工作:

package main

import "fmt"

type MyString struct {
    string
    someState int
}

func (m MyString) String() string {
    return string(m.string)
}

func main() {
    // The verbose version: 
    //var a MyString = MyString{string: "a", someState: 1}

    a := MyString{"a", 1}

    fmt.Printf("A is: %s\n", a)
    fmt.Printf("A is: %s\n", a.String())
}

Go Playground链接:https://play.golang.org/p/GEKeY4rmB8

英文:

<h1>The original question</h1>
I have the following Go code. I would like to handle Foo a struct or Bar a type as a string. With "handle" I mean that I would like to convert/cast/whatever it's underlaying value to the (real) type string. I have a workaround, but I find it unintuitive in the case of a struct.

Going for a Type (instead of a struct) seems the better approach. I don't need to maintain any state, nor do I have any need for "inheriting" type specific functionality, so in my case it should work. However a call to type.String() causes stack recursion. I'm mostly curious if I'm not missing something (obvious).

package main

import &quot;fmt&quot;

type Foo struct {
	string
}

func (f *Foo) String() string {
	return f.string
}


type Bar string

func (b *Bar) String() string {
	return fmt.Sprintf(&quot;%s&quot;, b) // Cannot use: return string(b) here.
}

func main() {
	a := Foo{&quot;a&quot;}
	var b Bar
	b = &quot;b&quot;

	fmt.Printf(&quot;A is: %s\n&quot;, a) // Doesn&#39;t call a.String() ?
	//fmt.Printf(&quot;A is: %s\n&quot;, string(a)) // Doesn&#39;t work
	fmt.Printf(&quot;A is: %s\n&quot;, a.string)   // workaround A
	fmt.Printf(&quot;A is: %s\n&quot;, a.String()) // workaround B, required if I want to use it in a different package

	fmt.Printf(&quot;B is: %s\n&quot;, b) // Calls b.String()
	fmt.Printf(&quot;B is: %s\n&quot;, string(b))
    //fmt.Printf(&quot;B is: %s\n&quot;, b.String()) // Causes a stack overflow
}

Output:

A is: {a}
A is: a
A is: a
B is: b
B is: b

Code on Go's Playground: https://play.golang.org/p/zgrKao4cxa
The behaviour is from Go version 1.5.2

<h1>Answers</h1>
The following are short examples based on the answers of my original questions. Also, the following post helped in understanding and reasoning of the subject: https://stackoverflow.com/questions/27775376/value-receiver-vs-pointer-receiver-in-golang

In case of a type, the following works:

type MyString string

func (b MyString) String() string {
	return string(b)
}

Go's Playground link: https://play.golang.org/p/H12bteAk8D

In case of a struct, the following works:

package main

import &quot;fmt&quot;

type MyString struct {
	string
	someState int
}

func (m MyString) String() string {
	return string(m.string)
}

func main() {
	// The verbose version: 
	//var a MyString = MyString{string: &quot;a&quot;, someState: 1}

	a := MyString{&quot;a&quot;, 1}

	fmt.Printf(&quot;A is: %s\n&quot;, a)
	fmt.Printf(&quot;A is: %s\n&quot;, a.String())
}

Go's Playground link: https://play.golang.org/p/GEKeY4rmB8

答案1

得分: 0

你为String方法创建了指针接收器,但你正在处理的是值,而不是指向它们的指针,所以这不适用。你需要切换到指针或更改String方法的签名:

package main

import "fmt"

type Foo struct {
    string
}

func (f Foo) String() string {
    return "My " + f.string
}

type Bar string

func (b Bar) String() string {
    return fmt.Sprintf("My %s", string(b))
}

func main() {
    a := Foo{"a"}
    var b Bar = "b"

    fmt.Printf("A is: %s\n", a)
    fmt.Printf("B is: %s\n", b)
}

请注意接收器类型

关于指针和值的接收器的规则是,值方法可以在指针和值上调用,但指针方法只能在指针上调用。

哦,还有一件事。如果定义了String方法,fmt.Sprintf("%s", b)将调用该方法。所以会出现递归。

英文:

You've made a pointer receivers for your String methods, but you are working with values, not pointers to them, so it wouldn't apply. You need to switch to pointers or change String methods signatures:

package main

import &quot;fmt&quot;

type Foo struct {
	string
}

func (f Foo) String() string {
	return &quot;My &quot; + f.string
}

type Bar string

func (b Bar) String() string {
	return fmt.Sprintf(&quot;My %s&quot;, string(b))
}

func main() {
	a := Foo{&quot;a&quot;}
	var b Bar = &quot;b&quot;

	fmt.Printf(&quot;A is: %s\n&quot;, a)
	fmt.Printf(&quot;B is: %s\n&quot;, b)
}

Please, be careful with receivers type:

> The rule about pointers vs. values for receivers is that value methods
> can be invoked on pointers and values, but pointer methods can only be
> invoked on pointers

Oh, and one more thing. fmt.Sprintf(&quot;%s&quot;, b) will call String method if it's defined. So, you'll get a recursion.

huangapple
  • 本文由 发表于 2016年1月25日 18:34:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/34990417.html
匿名

发表评论

匿名网友

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

确定