【问题标题】:How to convert a user-defined named type/struct to it's anonymous type如何将用户定义的命名类型/结构转换为它的匿名类型
【发布时间】:2016-01-25 10:34:17
【问题描述】:

原来的问题

我有以下 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) // 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
}

输出:

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

Go 游乐场代码:https://play.golang.org/p/zgrKao4cxa 该行为来自 Go 版本 1.5.2

答案

以下是基于我最初问题的答案的简短示例。此外,以下帖子有助于理解和推理该主题:Value receiver vs. Pointer receiver in Golang?

在类型的情况下,以下工作:

type MyString string

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

Go 的游乐场链接: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

【问题讨论】:

  • b 的 String() 函数可以使用return string(*b),不需要 sprintf 的值。只需要匹配函数的返回类型
  • 啊,你是对的。我不敢相信我错过了。我想我被错误消息cannot convert b (type *Bar) to type string 吓跑了。感谢您的帮助。
  • @Dynom 请不要为您的问题添加答案。如果您有一些有趣的信息要分享,请在下方添加您自己的答案。

标签: go


【解决方案1】:

您已经为 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)
}

请注意receivers type:

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

哦,还有一件事。 fmt.Sprintf("%s", b) 将调用 String 方法(如果已定义)。所以,你会得到一个递归。

【讨论】:

  • 其实这很有意义。但是为什么在方法中取消引用不起作用?我已经尝试过了,但这不起作用: func (f *Foo) String() string { return (*f).string }
  • 当你传递 printf a 时,你传递的是值 a。将其更改为 &a (指向 a 的指针),您的 String() 函数将被调用(从您的播放示例中的第 24 行开始)。但是传递指向字符串的指针并不奇怪,所以这个答案更有意义
  • @Dynom, "接收者的指针与值的规则是值方法可以在指针和值上调用,但指针方法只能在指针上调用"
  • 好吧,这有帮助。感谢您的解释!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-19
  • 1970-01-01
  • 2010-11-27
  • 1970-01-01
  • 2012-05-01
  • 2020-04-18
  • 2012-01-20
相关资源
最近更新 更多