英文:
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 "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) // Cannot use: return string(b) here.
}
func main() {
a := Foo{"a"}
var b Bar
b = "b"
fmt.Printf("A is: %s\n", a) // Doesn't call a.String() ?
//fmt.Printf("A is: %s\n", string(a)) // Doesn't work
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) // Calls b.String()
fmt.Printf("B is: %s\n", string(b))
//fmt.Printf("B is: %s\n", 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 "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'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 "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)
}
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("%s", b)
will call String
method if it's defined. So, you'll get a recursion.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论