In https://tour.golang.org/methods/11
It states Under the hood, interface values can be thought of as a tuple of a value and a concrete type
I define M as follows
script1
package main
import (
"fmt"
)
type I interface {
M() string
}
type T struct {
S string
w string
}
func (t T) M() string {
return "dddd"
}
func main() {
var i I
i = T{"Hello","eeee"}
fmt.Printf("(%v, %T)", i, i)
fmt.Println(i)
}
This prints out ({Hello eee}, main.T){Hello eee}
interface i has vaule {Hello eee} and type main.T
script2:
package main
import (
"fmt"
)
type I interface {
M() string
}
type T struct {
S string
w string
}
func (t T) M() string {
return "dddd"
}
func (t T) String() string {
return "ccccc"
}
func main() {
var i I
i = T{"Hello","eeee"}
fmt.Printf("(%v, %T)", i, i)
fmt.Println(i)
}
This prints out (ccccc, main.T)ccccc.
interface i has vaule ccccc and type main.T
Seems when i add String() as Stringer defined by the fmt package in script2. The String() is implemented implicitily,not sure why?
I thought in script2 i would have value "{Hello eee}" and type main.T
You should call fmt.Println(i.M()) ?
Why you want fmt call a function while its'n exist?
A Stringer is a type that can describe itself as a string. The fmt package (and many others) look for this interface to print values
Refer: https://golang.org/pkg/fmt/#Stringer
Stringer is implemented by any value that has a String method, which
defines the “native” format for that value. The String method is used
to print values passed as an operand to any format that accepts a
string or to an unformatted printer such as Print.
In your case, in script1 you are just printing out the struct. In script2 you are providing what the builder should use when an unformatted print occurs which is a function that prints out "ccccc".
Related
In this bizarre example, someone has created a new type which is really just a string:
type CustomType string
const (
Foobar CustomType = "somestring"
)
func SomeFunction() string {
return Foobar
}
However, this code fails to compile:
cannot use Foobar (type CustomType) as type string in return argument
How would you fix SomeFunction so that it is able to return the string value of Foobar ("somestring") ?
Convert the value to a string:
func SomeFunction() string {
return string(Foobar)
}
Better to define a String function for the Customtype - it can make your life easier over time - you have better control over things as and if the structure evolves. If you really need SomeFunction then let it return Foobar.String()
package main
import (
"fmt"
)
type CustomType string
const (
Foobar CustomType = "somestring"
)
func main() {
fmt.Println("Hello, playground", Foobar)
fmt.Printf("%s", Foobar)
fmt.Println("\n\n")
fmt.Println(SomeFunction())
}
func (c CustomType) String() string {
fmt.Println("Executing String() for CustomType!")
return string(c)
}
func SomeFunction() string {
return Foobar.String()
}
https://play.golang.org/p/jMKMcQjQj3
For every type T, there is a corresponding conversion operation T(x)
that converts the value x to type T. A conversion from one type to
another is allowed if both have the same underlying type, or if both
are unnamed pointer types that point to variables of the same
underlying type; these conversions change the type but not the
representation of the value. If x is assignable to T, a conversion
is permitted but is usually redundant. - Taken from The Go
Programming Language - by Alan A. A. Donovan
As per your example here are some of the different examples which will return the value.
package main
import "fmt"
type CustomType string
const (
Foobar CustomType = "somestring"
)
func SomeFunction() CustomType {
return Foobar
}
func SomeOtherFunction() string {
return string(Foobar)
}
func SomeOtherFunction2() CustomType {
return CustomType("somestring") // Here value is a static string.
}
func main() {
fmt.Println(SomeFunction())
fmt.Println(SomeOtherFunction())
fmt.Println(SomeOtherFunction2())
}
It will output:
somestring
somestring
somestring
The Go Playground link
You can convert like this:
var i int = 42
var f float64 = float64(i)
check here
you can return like this:
return string(Foobar)
When my function is given an interface argument that is a pointer I would like to update the pointer to something else (a* = b*). If the function argument is not an interface and is instead a pointer, this works fine.
Given the following code:
package main
import "fmt"
type demoInterface interface {
GetName() string
}
type demoStruct struct {
name string
}
func (d demoStruct ) GetName() string {
return d.name
}
func Update(d1 demoInterface) {
fmt.Println(d1)
d2 := demoStruct{name: "bob"}
d1 = &d2
fmt.Println(d1)
}
func main() {
d1 := &demoStruct{name: "frank"}
fmt.Println(d1)
Update(d1)
fmt.Println(d1)
}
The output is
&{frank}
&{frank}
&{bob}
&{frank}
However I would actually expect
&{frank}
&{frank}
&{bob}
&{bob}
If I replace the Update function signature to accept a *demoStruct instead of a demoInterface it works as expected.
Is there a way to get this to work as expected when the functions signature is an interface rather than a pointer.
Thanks.
If you really need this, it could be one of the rare cases where a pointer to an interface may make sense. Here's your example modified with that:
package main
import "fmt"
type demoInterface interface {
GetName() string
}
type demoStruct struct {
name string
}
func (d demoStruct ) GetName() string {
return d.name
}
func Update(d1 *demoInterface) {
fmt.Println(*d1)
d2 := demoStruct{name: "bob"}
*d1 = d2
fmt.Println(*d1)
}
func main() {
d1 := demoInterface(demoStruct{name: "frank"})
fmt.Println(d1)
Update(&d1)
fmt.Println(d1)
}
Note that since Update takes *demoInterface, we can't just pass in *demoStruct (Go has no type covariance), so we have to convert the struct to the interface first.
Consider the following code. The first function is a receiver method for type MessageStr. Why fmt.Println(msgstr) executes the first method without calling the method as fmt.Println(msgstr.String()). Also why fmt.Println(msgint32) doesn't execute the second method.
package main
import (
"fmt"
)
type MessageStr string
type MessageInt32 int32
func (msgs MessageStr) String() string {
return string("<<" + msgs + ">>")
}
func (msgi MessageInt32) Int32() int32 {
return int32(msgi * 2)
}
func main() {
msgstr := MessageStr("Mastering Go")
// why this outputs <<Mastering Go>>
// without calling the String() method
fmt.Println(msgstr)
msgint32 := MessageInt32(11)
// why this doesn't output 11*2 = 22
fmt.Println(msgint32)
fmt.Println(msgint32.Int32())
}
When you call fmt.Println, it expects an object that implements the Stringer interface. It's documented as follows:
If an operand implements method String() string, that method will be
invoked to convert the object to a string, which will then be
formatted as required by the verb (if any)
The fmt package also declares the Stringer interface:
type Stringer interface {
String() string
}
Such objects must have a String() method that takes no arguments and returns a string. fmt.Println then invokes the String method. This lets us define for custom types how they're going to be printed out. For example:
package main
import "fmt"
type Person struct {
name string
age int
}
func (p Person) String() string {
return fmt.Sprintf("%s<%d>", p.name, p.age)
}
func main() {
p := Person{name: "Joe", age: 39}
fmt.Println(p)
}
Will print out:
Joe<39>
Because we've customized the way Person objects are turned into strings. More details:
Interfaces in the Go tour
Stringer in the Go tour
If you're interested in the mechanics of how this actually happens in the fmt package, take a look at the handleMethods method in src/fmt/print.go.
When printing a struct with nested struct which has a String() implemented, the %v format prints an 'unexpected' value per our understanding.
Below is the code snippet.
package main
import (
"fmt"
)
type Inner struct {
}
type A struct {
Inner
FieldA string
}
func (i Inner) String() string {
return "anything"
}
func main() {
myA := A{FieldA: "A"}
fmt.Printf("%v", myA)
}
We expect the output to be
{anything A}
But the actual result is
anything
Why this result? It seems FieldA is ignored? To make it more confusing, if we have two nested structs where both of them have String() implemented, the output is expected.
package main
import (
"fmt"
)
type Inner struct {
}
type InnerAgain struct {
}
type A struct {
Inner
InnerAgain
FieldA string
}
func (i Inner) String() string {
return "anything"
}
func (i InnerAgain) String() string {
return "nothing"
}
func main() {
myA := A{FieldA: "A"}
fmt.Printf("%v", myA)
}
The output is
{anything nothing A}
...
Since you are embedding Inner, you inherent all its properties - including the String() - function. So %v is actually calling Inner.String()
From the docs (https://golang.org/pkg/fmt/) :
If an operand implements method String() string, that method will
be invoked to convert the object to a string, which will then be
formatted as required by the verb (if any).
Because the fmt package states the rules for %v as:
If the format (which is implicitly %v for Println etc.) is valid for a string (%s %q %v %x %X), the following two rules apply:
If an operand implements the error interface, the Error method will be invoked to convert the object to a string, which will then be formatted as required by the verb (if any).
If an operand implements method String() string, that method will be invoked to convert the object to a string, which will then be formatted as required by the verb (if any).
Hence, %v actually uses the String() method for arguments that are stringers.
In the following code, I would expect fmt.Printf("%v\n", a) to invoke String() of its member of type myTypeB, but this is not happening ? Why ?
package main
import "fmt"
type myTypeA struct {
b myTypeB
}
type myTypeB struct {
c string
d int
}
func (b myTypeB) String() string {
return "myTypeB custom"
}
func main() {
a:= myTypeA{myTypeB{"hello", 1}};
b:= myTypeB{"hello", 1}
fmt.Printf("%v\n", a)
fmt.Printf("%v\n", b)
}
Playground link
fmt doesn't look for fmt.Stringer recursively.
If the argument is a fmt.Stringer, it will invoke the String() method, and print the results. If it doesn't have a String() method, fmt will iterate over the fields using reflection to obtain the value.