If I try a file like this:
package main
import "time"
type Alpha time.Time
func main() {
o := Alpha.Now()
n := o.Unix()
println(n)
}
I get this result:
Alpha.Now undefined (type Alpha has no method Now)
However it works with other languages. For example PHP:
<?php
class Alpha extends DateTime {}
$o = new Alpha;
$n = $o->getTimestamp();
var_dump($n);
It is possible with Go, to create a new type that has access to the methods of
another type?
First of all, time.Now() is just a package-level function, not a method of any type. Thus, the proper way to invoke it would look like smth := time.Time(), not smth := time.Time.Now().
We can take a closer look at the function. It's defined in package time and currently implemented as follows:
func Now() Time {
sec, nsec, mono := now()
mono -= startNano
sec += unixToInternal - minWall
if uint64(sec)>>33 != 0 {
return Time{uint64(nsec), sec + minWall, Local}
}
return Time{hasMonotonic | uint64(sec)<<nsecShift | uint64(nsec), mono, Local}
}
As you can see, it returns an object of type time.Time. Which then can be used for the consequent .Unix() method call:
func (t Time) Unix() int64 {
return t.unixSec()
}
In case of Unix() it's a true method with the receiver of type time.Time.
For the extension part of your question, you can use the following trick:
package main
import "time"
type Alpha struct {
time.Time
}
func main() {
o := time.Now()
a := Alpha { o }
n := a.Unix()
println(n)
}
Go doesn't provide any model of inheritance. However, its composition capabilities are very powerful. The code from the snippet above basically creates a new struct type Alpha with an anonymous attribute of type time.Time. However, due to the fact that the explicit name of this attribute is skipped, we can access methods of a contained time.Time instance right through the parent structure. The technique is called Embedding.
Related
In a db package, I don't want to expose MongoDB's primitive.ObjectID type as part of its public API. Instead, I want to define type Id interface{} within the db package and expose that. Since the driver doesn't know how to transform the database's ObjectID type into my custom ID type, I registered a type decoder like so:
type Id interface{}
var idType = reflect.TypeOf((*Id)(nil)).Elem()
type User struct {
Id `bson:"_id,omitempty"`
}
func main() {
reg := bson.NewRegistryBuilder().
RegisterTypeDecoder(idType, bsoncodec.ValueDecoderFunc(idDecodeValue)).
Build()
client, err := mongo.Connect(context.TODO(), options.Client().
ApplyURI("...").
SetRegistry(reg))
coll := client.Database("...").Collection("...")
var u0 User
coll.InsertOne(context.TODO(), u0)
var u1 User
coll.FindOne(context.TODO(), bson.D{}).Decode(&u1)
}
func idDecodeValue(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.IsValid() || val.Type() != idType {
return bsoncodec.ValueDecoderError{
Name: "IdDecodeValue",
Types: []reflect.Type{idType},
Received: val,
}
}
oid, _ := vr.ReadObjectID()
val.Set(reflect.ValueOf(oid))
return nil
}
I saw that there exists a bsoncodec.NewEmptyInterfaceCodec() to use in place of idDecodeValue, but that only seems to work when User.Id's type is exactly interface{}. I wrote idDecodeValue based off of the existing codecs, but I'm not entirely sure what's going on (mostly due to not knowing when val.IsValid() would ever return false). Is all of this the best, most idiomatic way to go about supporting a custom ID type?
This question already has answers here:
How to set and get fields in struct's method
(3 answers)
Assign a new value to a struct field
(2 answers)
Struct field reverts [duplicate]
(1 answer)
Closed 5 years ago.
I'm just starting out with Go and I'm having a hard time saving data in a struct. Coming from other languages I learned there is no such thing as a class in Go. For similar purposes, the struct can be used, and functions can be "added" to the struct. So I wrote the following simple program:
package main
import "fmt"
type MyStruct struct {
the_number int
}
func (self MyStruct) add(another_number int) int {
self.the_number += another_number // I save the result to the struct the_number
return self.the_number
}
func main() {
my_struct := MyStruct{1}
result := my_struct.add(2)
fmt.Println(result) // prints out 3 as expected
fmt.Println(my_struct.the_number) // prints out 1. Why not also 3?
}
As you can see from the comments I'm puzzled by the fact that the result is not saved in self.the_number in the instantiated my_struct.
So I found out I can get around this by doing
my_struct.the_number = my_struct.add(2)
But I methods/functions can sometimes become complex in which I want to save a lot of data to the my_struct from within the function.
Could any smarter soul than me give me a tip on what I'm missing here?
How can I save data to an instantiated struct from within a function?
You should use pointer in struct method func (self *MyStruct) add(another_number int) int as without the * variable (self) is passed by value, not by references. E.g. you are updating a copy of an original object and this changes are discarded.
It's a basic stuff and well covered in Tour of Go - everyone should take it before starting coding in Go.
Another option would be return the self from the method - it would follow "immutable" style so you can write code like: my_struct = my_struct.add(1).add(2)
package main
import "fmt"
type MyStruct struct {
the_number int
}
func (self *MyStruct) add(another_number int) int {
self.the_number += another_number
return self.the_number
}
func main() {
my_struct := MyStruct{1}
result := my_struct.add(2)
fmt.Println(result) // prints out 3 as expected
fmt.Println(my_struct.the_number) // prints out 1. Why not also 3?
}
How can I make the RemoveDead function accept other slices of interfaces (or maybe even slices of struct pointers) that implement Liver with little impact on performance?
It seems to me that the function would have to take an interface{} as argument and do runtime conversions, but I'm not sure how to do the conversions. I would also guess that doing x.(Liver) is a lot slower than Liver(x), because the latter is a compile time conversion.
Is the best solution to copy-paste the function and change the argument and return type in each copy? Only three or four copies would be needed, but it would still feel like a very clumsy solution.
type Updater interface {
Liver
Update() bool
}
type Liver interface {
Alive() bool
}
func RemoveDead(all []Updater) []Updater {
for i := len(all) - 1; i >= 0; i-- {
if Liver(all[i]).Alive() == false {
all[i] = all[len(all)-1]
all = all[:len(all)-1]
}
}
return all
}
As you mentioned, a slice of type []Updater cannot be turned to a []Liver with a simple type assertion; their type are not interfaces, but slices of interfaces. For the same reason is it not possible to pass a []Updater to a function wanting an []interface{} as parameter.
However, you can do what you desire using the reflect package. Reflection is useful but will come at a cost on performance. If you consider the cost to high, then you will probably have to use the copy-paste solution.
The code below can surely be improved, but it shows how to solve the problem with reflection, and it might be useful when making a benchmark. Currently it regards any even U value as Alive:
package main
import (
"fmt"
"reflect"
)
type Updater interface {
Alive() bool
Update() bool
}
type Liver interface {
Alive() bool
}
type U int
func (u U) Alive() bool { return u % 2 == 0 }
func RemoveDead(all interface{}) interface{} {
v := reflect.ValueOf(all)
if v.Kind() != reflect.Slice {
panic("RemoveDead requires a slice")
}
for i := v.Len() - 1; i >= 0; i-- {
l := v.Index(i)
if l.Interface().(Liver).Alive() == false {
l.Set(v.Index(v.Len()-1))
v = v.Slice(0, v.Len()-1)
}
}
return v.Interface()
}
func main() {
u := []U{1,4,7,2,12}
fmt.Println("Before: ", u)
u = RemoveDead(u).([]U)
fmt.Println("After: ", u)
}
Output:
Before: [1 4 7 2 12]
After: [2 4 12]
Playground
You could define third interface:
type UpdaterLiver interface {
Updater
Liver
}
then change definition of RemoveDead to be
func RemoveDead(all []UpdaterLiver) []UpdaterLiver
Using golang html/template (same behavior with text/template). If I have a struct with a member that is of an interface type, I cannot access members of the underlying type (specifically trying to access fields that are on a struct that implements interface InnerInterface but is return via the InnerInterface interface type, not the struct type).
http://play.golang.org/p/ZH8wSK83oM
package main
import "fmt"
import "os"
import "html/template"
type InnerInterface interface{ InnerSomeMethod() }
type MyInnerStruct struct { Title string }
func (mis MyInnerStruct)InnerSomeMethod() { fmt.Println("Just to show we're satisfying the interface") }
type MyOuterStruct struct { Inner InnerInterface }
func main() {
fmt.Println("Starting")
arg := MyOuterStruct{Inner:MyInnerStruct{Title:"test1"}}
err := template.Must(template.New("testtmpl").Parse("{{.Inner.Title}}")).Execute(os.Stdout, arg)
if err != nil { panic(err) }
}
Changing: type MyOuterStruct struct { Inner InnerInterface } to a totally generic interface, i.e. type MyOuterStruct struct { Inner interface{} } makes it render properly. This leads me to believe that interface{} is treated specially by the rendering engine.
Is there a better way to do this than to use interface{} whenever I want to be able to dynamically evaluate fields like this?
You're correct with saying that interface{} is handled differently by the rendering
engine. Only interface{} values are unpacked, interface values that have a method set are not.
I suppose the reasoning behind this is that if you have a interface type, you specifically limit the type to the method set. Therefore, you don't want the template engine trying to access members that may lie behind that interface.
The 'problem' is caused by the function indirect in exec.go:
func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
if v.IsNil() {
return v, true
}
if v.Kind() == reflect.Interface && v.NumMethod() > 0 {
break
}
}
return v, false
}
This method is called to get to the deepest value of a reflected value.
Suppose you have a pointer on a pointer on a pointer, this function will get return the
last of these. The same goes for interface values. The crux is that as soon as a
interface value has more than 0 methods, the indirection stops there. Exactly the
behaviour you're describing.
As this seems to be intended behaviour, what you can do is to define a Title() string
method in your interface and let it return the string.
If I have a struct and I want to get it's key, but it's currently of type interface{} how do I do that?
Currently I get the following compilation error:
invalid operation: d[label] (index of type interface {})
Play: http://play.golang.org/p/PLr91d55GX
package main
import "fmt"
import "reflect"
type Test struct {
s string
}
func main() {
test := Test{s: "blah"}
fmt.Println(getProp(test, "s"))
}
func getProp(d interface{}, label string) (interface{}, bool) {
switch reflect.TypeOf(d).Kind() {
case reflect.Struct:
_, ok := reflect.TypeOf(d).FieldByName(label)
if ok {
// errors here because interface{} doesn't have index of type
return d[label], true
} else {
return nil, false
}
}
}
Do I really have to do the massive case statement on each different type and call the reflected reflect.ValueOf(x).String() etc? I'm hoping there is a more elegant way.
You could do this, however I think it'll only work if your struct member s was an exported field (i.e. use a capital S in your example)
func getProp(d interface{}, label string) (interface{}, bool) {
switch reflect.TypeOf(d).Kind() {
case reflect.Struct:
v := reflect.ValueOf(d).FieldByName(label)
return v.Interface(), true
}
return nil, false
}
(+ some more error handling)
I'm not sure exactly what you're looking for, but there is a slightly simpler way to look for interface{} types. In your case, you could use:
switch val := d.(type) {
case Test:
fmt.Println(d.s)
}
Obviously, I'm not doing the same thing as you were, but the idea is that you can check the type with "d.(type)", and once "case Test:" determines that it is a struct of your Test type, you can access it as such.
Unfortunately, this doesn't address the accessing of the value within the struct by the label, but it at least is a more elegant way of determining the type, and #nos shows how to do that with
v := reflect.ValueOf(d).FieldByName(label)
return v.Interface(), true