Why this String() method is called without calling it by name - go

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.

Related

Why my Golang defined method not implemented implicitily while String() does

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".

Why %v is printing unexpected value for nested struct?

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.

Modify struct fields during instance generation

Foreign application API gives me a list of names in JSON format. I need modify all of those.
But I do not like to write some loop for it (especially after Python using with reflection and stuff)
Is there any method to write something like this in Go?
type MyIncredibleType struct {
Name ModifyName // ModifyName is not a type!
}
func ModifyName(input string) string {
return input + ".com"
}
The expected behavior of this is:
a := MyIncredibleType{Name: "Abracadabra"}
print(a.Name) // Abracadabra.com
This seems pretty straight forward to me, assuming I understand your question correctly:
// ModifyName func
func ModifyName(input string) string {
return fmt.Sprintf("%v.com", input)
}
If you wish to achieve this within the type itself, without modifying (mutating) the internal state:
type MyType sturct {
name string // unexported
}
// accessor func to return name
func (t MyType) Name() string {
return t.name
}
// accessor func to return modified name
func (t MyType) ModifiedName() string {
return fmt.Sprintf("%v.com", t.name)
}
If you want to modify the internal state:
type MyType struct {
name string
}
// mutator func (note the pointer for pass by reference)
func (t *MyType) ModifyName(input string) {
t.name = fmt.Sprintf("%v.com", input)
}
// accessor (note no pointer for pass by value)
func (t MyType) Name() string {
return t.name
}
This is is not possible in GO. That's not how struct works in Go.
type MyIncredibleType struct {
Name ModifyName `json:"name"` // ModifyName is not a type!
}
you can only define Built-in types for your fields of struct or you can define Composite Literal types.
Composite literals construct values for structs, arrays, slices, and
maps and create a new value each time they are evaluated. They consist
of the type of the literal followed by a brace-bound list of elements.
Each element may optionally be preceded by a corresponding key.
Try to create a method receiver of struct which you are using to parse json coming from the api to modify the name. That will let you achieve something similar to what you want.
package main
import (
"fmt"
)
type MyIncredibleType struct {
Name string `json:"name"` // ModifyName is not a type!
}
func(myIncredibleType *MyIncredibleType) ModifyName() string {
return myIncredibleType.Name+".com"
}
func main() {
a := MyIncredibleType{Name: "Abracadabra"}
name := a.ModifyName()
fmt.Printf("%s",name)
}
Playground Example
Or you can pass an interface which will wrap any struct value with name field and then use Type assertion to get the underlying value to modify the same and return the result:
package main
import (
"fmt"
)
type MyIncredibleType struct {
Name string `json:"name"` // ModifyName is not a type!
}
func ModifyName(input interface{}) string{
return input.(interface{}).(string)+".com"
}
func main() {
a := MyIncredibleType{Name: "Abracadabra"}
name := ModifyName(a.Name)
fmt.Printf("%s",name)
}
Working code on Go Playground
For more information also go through Golang method Declarations on how to create receivers.

Go type assertion with interface don't understand how does it

I'm reading "Go Bootcamp" and there is an example in the Chapter 3, page 20 I cannot understand. In this example, in the line printString(s), s is a variable of type fakeString, but in the switch, enters in the "Stringer" case. I'm trying to understand how is this possible. Any help would be appreciated.
The code is:
package main
import "fmt"
type Stringer interface {
String() string
}
type fakeString struct {
content string
}
// function used to implement the Stringer interface
func (s *fakeString) String() string {
return s.content
}
func printString(value interface{}) {
switch str := value.(type) {
case string:
fmt.Println(str)
case Stringer:
fmt.Println(str.String())
}
}
func main() {
s := &fakeString{"Ceci n'est pas un string"}
printString(s)
printString("Hello, Gophers")
}
Because the fakeString is a different type than string, but it implements Stringer interface. Every type with given function implements the type. The fakeString contains the String() func so it also implements Stringer interface. This is some kind of fundamental stones of Go.
Check the built-in libs for Reader interface, it is usually given as an example for this.

Private fields and methods for a struct

In the following test code I would like to have both mytype and the doPrivate method private, so that only members of mytype can access it, but not other types\functions in the scope of the mypackage package.
Can I do this in golang?
package mypackage
type mytype struct {
size string
hash uint32
}
func (r *mytype) doPrivate() string {
return r.size
}
func (r *mytype) Do() string {
return doPrivate("dsdsd")
}
Fields size and hash as well as the doPrivate method should be encapsulated and no other type should have access to them.
In Go, an identifier that starts with a capital letter is exported from the package, and can be accessed by anyone outside the package that declares it.
If an identifier starts with a lower case letter, it can only be accessed from within the package.
If you need members in a type to only be accessed by members of that type, you then need to place that type and its member functions in a separate package, as the only type in that package.
That's not how "privacy" works in Go: the granularity of privacy is the package.
If you really want only the members of mytype to access some fields, then you must isolate the struct and the functions in their own package.
But that's not the usual practice. Whether Go is OOP or not is debatable but clearly the practice isn't to encapsulate the code by a struct like you seem to want to do. Usually a package is small enough to be coherent: if you don't want to access fields from within the package, don't access them.
You can create an interface with the method you wish to expose and only access the object when wrapped into that interface.
package main
type mytype struct {
size string
hash uint32
}
// interface for exposed methods
type myinterface interface {
do() string
}
// constructor (optional)
func newMytype(size string, hash uint32) myinterface {
return &mytype{size, hash}
}
func (r *mytype) doPrivate() string {
return r.size
}
func (r *mytype) do() string {
return r.doPrivate()
}
func main() {
// with constructor
t := newMytype("100", 100)
t.do()
// t.doPrivate() // t.doPrivate undefined (type myinterface has no field or method doPrivate)
// without constructor
t2:= myinterface(&mytype{"100", 100})
t2.do()
// t.doPrivate() // t.doPrivate undefined (type myinterface has no field or method doPrivate)doPrivate)
}
https://play.golang.org/p/awjIIj8Kwms
You cannot do this in Go. Visibility is on a per package level only. But you may split your package into two.
In one module there can be any number of packages.
Public/Private works only across one package.
All public fields, methods and functions starts with uppercase char.
All private fields, methods and functions starts with lowercase char.
To add package to your module or program just create a lowercase folder and add package name to all files inside. Here is the example.
./main.go
./foo/foo.go
./foo/MyStruct.go
file ./foo/foo.go:
package foo
import "fmt"
func SomePublicFuncInFoo() {
somePrivateFuncInFoo()
}
func somePrivateFuncInFoo() {
fmt.Println("somePrivateFuncInFoo call")
}
file ./foo/MyStruct.go:
package foo
import "fmt"
type MyStruct struct {
MyPublicField string // starts with uppercase char
myPrivateField string // starts with lowercase char
}
func NewMyStruct(publicField string, privateField string) *MyStruct {
return &MyStruct{
MyPublicField: publicField,
myPrivateField: privateField,
}
}
func (self *MyStruct) SomePublicMethod() {
self.privateMethod()
}
func (self *MyStruct) privateMethod() {
fmt.Println("MyStruct", self.MyPublicField, self.myPrivateField)
}
file ./main.go:
package main
import (
"fmt"
"{your-module-name}/foo" // this line should be added by your IDE
)
func main() {
foo.SomePublicFuncInFoo()
myStruct := foo.NewMyStruct("string1", "string2")
fmt.Println("myStruct.MyPublicField=", myStruct.MyPublicField)
myStruct.SomePublicMethod()
}
You can have private variables and functions in Go, but the trick is that you simply don't define them in the struct. Bind them to the call stack of a closure, and simply don't return them.
package main
import (
"fmt"
)
type mytype struct {
Do func() string
}
func MyType(size string, hash uint32) mytype {
doPrivate := func() string {
return size
}
return mytype{
Do: func() string {
return doPrivate()
},
}
}
func main() {
instance := MyType("100", 100)
fmt.Println(instance.Do())
}

Resources