In the code below, the invalid index access x[10] results in a panic. However, the panic message produced doesn't show the stack-trace of the error - rather, it looks like this: %!v(PANIC=String method: runtime error: index out of range [10] with length 3). Also, instead of terminating, the program keeps running after the panic occurs.
Based on this answer it seems that Println catches panics from String() methods and logs them. How do I prevent this behavior so that 1) my program terminates in the even of a panic in a String() method and 2) the full stack-trace of the panic is shown?
package main
import (
"fmt"
)
type Foo struct {
}
func (foo Foo) String() string {
var x = "123"
return fmt.Sprintf("%v", x[10]) // invalid index
}
func main() {
fmt.Println(Foo{})
fmt.Println("done")
}
Simply print the result of .String()
package main
import (
"fmt"
)
type Foo struct {
}
func (foo Foo) String() string {
var x = "123"
return fmt.Sprintf("%v", x[10])
}
func main() {
fmt.Println(Foo{}.String())
fmt.Println("done")
}
Related
The program below prints "2.5"
package main
import (
"fmt"
)
type myFloat64 float64
// func (f myFloat64) Error() string {
// return fmt.Sprintf("Error with %v", f)
// }
func main() {
var a myFloat64 = myFloat64(2.5)
fmt.Printf("%v\n", a)
}
Interestingly, when I uncomment the Error() method, the program no longer prints "2.5"
Question:
Why does adding an Error() method change program behavior? Pointers to the Go language specification explaining this behavior would be much appreciated.
myFloat64 implements the error interface:
type error interface {
Error() string
}
fmt.Println() will consider a as an error value, and print the error message by calling a.Error(), which executes fmt.Sprintf("Error with %v", f). But Sprintf behaves just like Println, it also considers f as an error value and calls Error(). This recursion goes infinitely and causes stack overflow.
I am playing around with type parameters (generics) using Go 1.18beta1.
Problem
Consider the following snippet:
package main
import (
"fmt"
)
func main() {
foo := &Foo[string, int]{
valueA: "i am a string",
valueB: 123,
}
fmt.Println(foo)
}
type Foo[T1 any, T2 any] struct {
valueA T1
valueB T2
}
func (f *Foo[_,_]) String() string {
return fmt.Sprintf("%v %v", f.valueA, f.valueB)
}
This snippet fails to build with the following error:
<autogenerated>:1: cannot use .this (type *Foo[string,int]) as type *Foo[go.shape.string_0,go.shape.string_0] in argument to (*Foo[go.shape.string_0,go.shape.int_1]).String
I attempted to use _ in the method declaration because of the following statement in the Type Parameters Proposal:
The type parameters listed in a method declaration need not have the same names as the type parameters in the type declaration. In particular, if they are not used by the method, they can be _.
Question
Is the build error above a bug in 1.18beta1 or am I missing something?
Snippet variations that build successfully
Use type parameter names
I can make the code build successfully if I change the String method declaration to the following (replace the _ with actual type parameters):
func (f *Foo[T1,T2]) String() string {
return fmt.Sprintf("%v %v", f.valueA, f.valueB)
}
Single type parameter
I managed to use the _ successfully when only using a single type parameter:
package main
import (
"fmt"
)
func main() {
foo := &Foo[string]{"i am a string"}
fmt.Println(foo)
}
type Foo[T1 any] struct {
value T1
}
func (f *Foo[_]) String() string {
return fmt.Sprintf("%v", f.value)
}
Instantiate Foo with same type for T1 and T2
_ also works in method declaration if Foo is instantiated with the same type (e.g. string for both T1 and T2):
package main
import (
"fmt"
)
func main() {
foo := &Foo[string, string]{
valueA: "i am a string",
valueB: "i am also a string",
}
fmt.Println(foo)
}
type Foo[T1 any, T2 any] struct {
valueA T1
valueB T2
}
func (f *Foo[_,_]) String() string {
return fmt.Sprintf("%v %v", f.valueA, f.valueB)
}
As mentioned in the comments of the question, the described behavior is a bug in Go 1.18beta1 and is being tracked by issue 50419.
Edit
I have confirmed that the bug in question is fixed in 1.18beta2, which was released on 31 January, 2022.
I was trying to generalize my code by using reflection to call all methods of a type. It's easy and straightforward but there is a problem with that, reflection.TypeOf(T).NumMethods (or other methods) ignores methods which used receiver type as a pointer.
For example this small code will print 1 instead of 2:
package main
import (
"fmt"
"reflect"
)
type Foo struct {}
func (f Foo) Bar() {}
func (f *Foo) Baz() {}
func main() {
obj := Foo{}
fmt.Println(reflect.TypeOf(obj).NumMethod())
}
You can run in playground.
It prints 1 because of Bar method. If you delete the pointer (*) from Baz, it will print 2.
My question is how can I list all methods regardless of receiver type.
Thanks
Get pointer to method with pointer type receiver. In case you wants to call the method by name using reflection here is the code.
package main
import (
"fmt"
"reflect"
)
type Foo struct{}
func (f Foo) Bar() {
fmt.Println("Inside Bar")
}
func (f *Foo) Baz() {
fmt.Println("Inside Baz")
}
func main() {
rfl := reflect.ValueOf(&Foo{})
v := rfl.MethodByName("Baz")
results := v.Call(nil)
fmt.Printf("%#v\n", results)
fmt.Println(reflect.TypeOf(&Foo{}).NumMethod())
}
Go Playground
You can just use the pointer of obj to get all Methods:
func main() {
obj := &Foo{}
fmt.Println(reflect.TypeOf(obj).NumMethod())
}
playground
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\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
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\n", a)
fmt.Printf("A is: %s\n", 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\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.
I have several methods that I'm calling for some cases (like Add, Delete, etc..). However over time the number of cases is increasing and my switch-case is getting longer. So I thought I'd create a map of methods, like Go map of functions; here the mapping of functions is trivial. However, is it possible to create a map of methods in Go?
When we have a method:
func (f *Foo) Add(a string, b int) { }
The syntax below create compile-time error:
actions := map[string]func(a, b){
"add": f.Add(a,b),
}
Is it possible to create a map of methods in Go?
Yes. Currently:
actions := map[string]func(a string, b int){
"add": func(a string, b int) { f.Add(a, b) },
}
Later: see the go11func document guelfi mentioned.
There is currently no way to store both receiver and method in a single value (unless you store it in a struct). This is currently worked on and it may change with Go 1.1 (see http://golang.org/s/go11func).
You may, however, assign a method to a function value (without a receiver) and pass the receiver to the value later:
package main
import "fmt"
type Foo struct {
n int
}
func (f *Foo) Bar(m int) int {
return f.n + m
}
func main() {
foo := &Foo{2}
f := (*Foo).Bar
fmt.Printf("%T\n", f)
fmt.Println(f(foo, 42))
}
This value can be stored in a map like anything else.
I met with a similar question.
How can this be done today, 9 years later:
the thing is that the receiver must be passed to the method map as the first argument. Which is pretty unusual.
package main
import (
"fmt"
"log"
)
type mType struct {
str string
}
func (m *mType) getStr(s string) {
fmt.Println(s)
fmt.Println(m.str)
}
var (
testmap = make(map[string]func(m *mType, s string))
)
func main() {
test := &mType{
str: "Internal string",
}
testmap["GetSTR"] = (*mType).getStr
method, ok := testmap["GetSTR"]
if !ok {
log.Fatal("something goes wrong")
}
method(test, "External string")
}
https://go.dev/play/p/yy3aR_kMzHP
You can do this using Method Expressions:
https://golang.org/ref/spec#Method_expressions
However, this makes the function take the receiver as a first argument:
actions := map[string]func(Foo, string, int){
"add": Foo.Add
}
Similarly, you can get a function with the signature func(*Foo, string, int) using (*Foo).Add
If you want to use pointer to type Foo as receiver, like in:
func (f *Foo) Add(a string, b int) { }
then you can map string to function of (*Foo, string, int), like this:
var operations = map[string]func(*Foo, string, int){
"add": (*Foo).Add,
"delete": (*Foo).Delete,
}
Then you would use it as:
var foo Foo = ...
var op string = GetOp() // "add", "delete", ...
operations[op](&foo, a, b)
where GetOp() returns an operation as string, for example from a user input.
a and b are your string and int arguments to methods.
This assumes that all methods have the same signatures. They can also have return value(s), again of the same type(s).
It is also possible to do this with Foo as receiver instead of *Foo. In that case we don't have to de-reference it in the map, and we pass foo instead of &foo.