Consider this code
import (
"fmt"
"math/big"
)
func main() {
var b1,b2,b3,bigSum big.Float
b1.SetFloat64(25.3)
b2.SetFloat64(76.2)
b1.SetFloat64(53.1)
bigSum.Add(&b1, &b2).Add(&b3, &bigSum)
fmt.Println(bigSum) // {53 0 0 1 false [9317046909104082944] 8}
fmt.Println(&bigSum) // 129.3
}
I have 2 questions
Why I have to pass bigSum as reference (by using &) to get the correct answer, otherwise we'll get back an object?
How does Println work in Go? I mean how does it know which format it should apply for different types?
Println determines whether the value implements the Stringer interface. If it does then it will call the String() to get formatted value. big.Float implements it for pointer receiver so you have to pass a reference. Otherwise Println will detect that it's a struct and print all of it's fields using reflection
Go is open sourced. You can see for yourself https://golang.org/src/fmt/print.go?#L738 It uses type switches and reflection.
Related
Just be curious, how to invoke the below go func func (t) test() if i declare it with type only receiver, is it even valid? like: https://play.golang.org/p/k8QukaCZdUN
package main
import (
"fmt"
)
type t int
func (t) test() {
fmt.Println(233)
}
func main() {
fmt.Println(666666)
}
I tried to build and run it, seems ok... but:
What exactly is this func (t) test() and how to invoke it?
Is there any meaningful use case for this kind of declaration (i mean bare type as receiver)?
More context:
I was triggered to think about this bcoz i want to find an idiomatic/elegant way to expose all values of an enum(iota) to external packages, currently i am doing something like: https://play.golang.org/p/iD0Aq_Mn2sj
package main
import (
"fmt"
)
type Gender int
const (
Male Gender = iota + 1
Female
)
func (g Gender) All() [2]string {
return [...]string{"MALE", "FEMALE"}
}
func main() {
fmt.Println("All gender types:", Gender(0).All())
}
It works, so any Gender instance can invoke its All function to get all the Gender types, but it feels a bit weird, so i start thinking of whether it is possible to register a func on the type only, not the instances, so i can do: package.Gender.All(), is it possible in go?
btw, no global var.
is it even valid?
As shown by your example, yes.
What exactly is this func (t) test() and how to invoke it?
It's a normal method. You invoke it like a normal method. See:
var val t
val.test()
Is there any meaningful use case for this kind of declaration (i mean bare type as receiver)?
The main difference with this form of method is that you can't access the receiver (as it's unnamed). So it's effectively similar to a "static" method (although it's really not. you still need an instance to call it)
If you want to get all values of an enum, there's no reason to make it a type method. All it does is create an extra step to call it:
var g Gender // create a useless variable so we can call the method
g.All() // actually call the method
You might as well make a regular function for it.
Is it possible to dynamically cast a value generated by reflect.Zero/New back to an arbitrary type?
https://blog.golang.org/laws-of-reflection seems to suggest not (as go is statically typed). That pretty much seems to limit the uses of reflection as far as I can see, as you always need to be aware of the type you are working with.
Here's an example of what I mean:
package main
import (
"fmt"
"reflect"
)
type A struct {
Name string
}
func main() {
a := &A{Name: "Dave"}
fmt.Println(a)
//create a nil pointer of an arbitrary type
dynamicType := reflect.TypeOf(a)
dynamicNil := reflect.Zero(dynamicType).Interface()
a = dynamicNil //is it possible to do this without explicitly casting to A (ie. avoiding `a = dynamicNil.(*A)`)
fmt.Println(a)
}
Your question's prose and code contradict.
In your code, dynamicNil has the type interface{}, not reflect.Value as the prose suggests. As a has concrete type *A you'll have to type-assert dynamicNil to *A. There's no way around that.
Also note that Go doesn't have casts -- only type-conversions and assertions.
Edit: maybe you're looking for reflect.Value.Set? it's unclear to me.
I need a way to dynamically cast a struct/interface back to its original object.
I can add methods / functions inside. basically I need something like this:
MyStruct => Interface{} => MyStruct
When on the final conversion I don't know anything about the original struct besides what come inside the struct, so I can't just so:
a.(MyStruct)
You need to know at least the possible types it could be. There's a couple cases, 1. You think you might know what it is. 2. You have a list of possible types it could be, 3. Your code knows nothing about the underlying types.
If you think you know it, you can use type assertion to convert back to the original struct type.
...
package main
import (
"fmt"
)
type MyStruct struct {
Thing string
}
func (s *MyStruct) Display() {
fmt.Println(s.Thing)
}
type Thingable interface {
Display()
}
func main() {
s := &MyStruct{
Thing: "Hello",
}
// print as MyThing
s.Display()
var thinger Thingable
thinger = s
// print as thingable interface
thinger.Display()
// convert thinger back to MyStruct
s2 := thinger.(*MyStruct) // this is "type assertion", you're asserting that thinger is a pointer to MyStruct. This will panic if thinger is not a *MyStruct
s2.Display()
}
You can see this in action here: https://play.golang.org/p/rL12Lrpqsyu
Note if you want to test the type without panicking if you're wrong, do s2, ok := thinger.(*MyStruct). ok will be true if it was successful and false otherwise.
if you want to test your interface variable against a bunch of types, use a switch: (scroll to bottom)
...
package main
import (
"fmt"
"reflect"
)
type MyStruct struct {
Thing string
}
type MyStruct2 struct {
Different string
}
func (s *MyStruct) Display() {
fmt.Println(s.Thing)
}
func (s *MyStruct2) Display() {
fmt.Println(s.Different)
}
type Thingable interface {
Display()
}
func main() {
s := &MyStruct{
Thing: "Hello",
}
// print as MyThing
s.Display()
var thinger Thingable
thinger = s
// print as thingable interface
thinger.Display()
// try to identify thinger
switch t := thinger.(type) {
case *MyStruct:
fmt.Println("thinger is a *MyStruct. Thing =", t.Thing)
case *MyStruct2:
fmt.Println("thinger is a *MyStruct2. Different =", t.Different)
default:
fmt.Println("thinger is an unknown type:", reflect.TypeOf(thinger))
}
}
You can try that out here https://play.golang.org/p/7NEbwB5j6Is
If you really don't know anything about the underlying types, you'll have to expose the things you need through interface functions and call those. Chances are you can do this without knowing anything about the underlying type. If all else fails, you can use the reflect package to introspect your interface object and gather information about it. this is how the json package reads json text and returns populated structs—though this is an advanced topic and expect to sink a lot of time into it if you go this route. it’s best to hide reflection code inside a package with a clean interface(ie the package api).
No: as mentioned in this thread
Go is neither covariant nor contravariant. Types are either equal or they aren't.
You have to either take the structs apart and deal with the pieces, or use reflection.
Type assertions are only "assertions", not "coercions" of any kind.
See also this thread, which reminds us that:
A pointer is one kind of type.
A struct is another kind of type.
An integer is another kind of type.
A floating point number is another kind of type.
A boolean is another kind of type.
The principle of an interface concerns the methods attached to a type T, not what type T is.
An interface type is defined by a set of methods.
Any value that implements the methods can be assigned to an interface value of that type.
That would make the conversion from interface to concrete type quite difficult to do.
Consider the following simple go program
package main
import (
"io"
"encoding/json"
"os"
)
type MyEncoder interface {
Encode(v interface{}) error
}
type MyEncoderCreator func(io.Writer) *MyEncoder
type MyContainer struct {
Creator MyEncoderCreator
}
func main() {
container := Container{
Creator:json.NewEncoder,
}
encoder := container.Creator(os.Stdout)
encoder.Encode(map[string]string{"key":"value"})
}
This program fails to compile with the following error:
./main.go:21: cannot use json.NewEncoder (type func(io.Writer) *json.Encoder) as type MyEncoderCreator in field value
Why is this? The json.Encoder struct has a receiver that satisfies the MyEncoder interface. So should the json.NewEncoder function be allowed to assigned to MyContainer.Creator?
Yes, a function has to satisfy the exact signature of the function type. Similar things come up in other contexts: a more formal way to say it is that generally types in Go lack covariance. Here, you could wrap json.NewEncoder in a function returning MyEncoder.
I'd use the value type MyEncoder not the pointer *MyEncoder because if you store a pointer inside the interface value then generally you don't also need a pointer to the interface value just to avoid copies; here's more on pointers vs. values if it helps.
I'm trying to use the stringer cmd so that I can generate String() methods for some int types. Here is how the code looks like
//go:generate stringer -type=MyIntType
type MyIntType int
const (
resource MyIntType = iota
)
func myfunc(){
print(resource.String())
}
The error I'm getting on go generate command is invalid operation: resource (constant 0 of type MyIntType) has no field or method String which makes sense because there is no String method yet. How am I supposed to fix this error if stringer cmd is supposed to actually generate the String method? Should I use fmt.Sprintf("%s", resource) all over the code ? it looks a bit ugly to me. At least not as nice as resource.String().
Each file must be parsed and type checked by the types library before the methods are generated. This usually doesn't pose a problem, since the String() method is rarely called directly, and is used by passing a value to something like fmt.Println that always checks first for a Stringer.
You can either not call String() yourself:
file: type.go
//go:generate stringer -type=MyIntType
package painkiller
import "fmt"
type MyIntType int
const (
resource MyIntType = iota
)
func myfunc() {
fmt.Println(resource)
}
Or you can put the calls in another file, and pass only the files that stringer needs as arguments. With no arguments, stringer checks the package as a whole, but if you provide only a list of files, they assume that some methods may be defined in files not provided.
file: type.go
//go:generate stringer -type=MyIntType type.go
package foo
type MyIntType int
const (
resource MyIntType = iota
)
file myfunc.go
package foo
func myfunc() {
print(resource.String())
}
The stringer cmd calls the go/parser.ParseFile for every go file. Thus if you have a method that is not declared it will fail. You will have to use fmt.Sprint* statements to get over this. Or you could tell go generate to only generate a specific file.
I don't know if we could term this as a bug. You could file it, probably see what the response is.