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

The original question

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
", a) // Doesn't call a.String() ?
    //fmt.Printf("A is: %s
", string(a)) // Doesn't work
    fmt.Printf("A is: %s
", a.string)   // workaround A
    fmt.Printf("A is: %s
", a.String()) // workaround B, required if I want to use it in a different package

    fmt.Printf("B is: %s
", b) // Calls b.String()
    fmt.Printf("B is: %s
", string(b))
    //fmt.Printf("B is: %s
", 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

Answers

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: 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
", a)
    fmt.Printf("A is: %s
", a.String())
}

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

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
", a)
    fmt.Printf("B is: %s
", 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.