Shouldn't the method explicitly contract with the signature of interface? - go

I am new with the golang, I am not quite understand why the below demo program could be executed successfully,
type fake interface {
getAge(valueInt int, valStr string) (age int, name string, err error)
}
type Foo struct {
name string
}
func (b *Foo) getAge(valueInt int, valStr string) (age int, retErr error) {
age = valueInt
return age, nil
}
func main() {
inst := &Foo{name:"foo"}
value, _ := inst.getAge(2, "foo")
fmt.Println(value)
}
The interface wants to return three value, but the method getAge only return two, but it still works. How to understand this behavior in golang?
Thanks!

Foo doesn't implement fake. This is apparent if you extend your code sample a bit (try it on the Go playground):
package main
import "fmt"
type fake interface {
getAge(valueInt int, valStr string) (age int, name string, err error)
}
type Foo struct {
name string
}
func (b *Foo) getAge(valueInt int, valStr string) (age int, retErr error) {
age = valueInt
return age, nil
}
func bar(f fake) {
_, name, _ := f.getAge(10, "")
}
func main() {
inst := &Foo{name: "foo"}
value, _ := inst.getAge(2, "foo")
fmt.Println(value)
bar(inst)
}
This produces a compile error that's pretty descriptive:
prog.go:28:5: cannot use inst (type *Foo) as type fake in argument to bar:
*Foo does not implement fake (wrong type for getAge method)
have getAge(int, string) (int, error)
want getAge(int, string) (int, string, error)

Related

Can I create a function with same signature as another?

I need to create a function that wraps an inner function, and has exactly the same signature as the inner function. I am fearing that this is not possible since Go does not support generics, but perhaps it is achievable using reflect? The following is the pseudo-go I would like to have:
func myFunc(a int, b string) (string, error) {
return string(a) + b, nil
}
func wrapInner(inner interface{}) interface{} {
argTypes := argsOf(inner)
returnTypes := returnsOf(inner)
wrapper := func(args argTypes) returnTypes {
// do something with inner's args
modArgs := doSomething(args)
ret := inner(modArgs)
// do something with the return
modRet := doSomething(ret)
}
return wrapper
}
wrapped := wrapInner(myFunc)
val, err := wrapped(1, "b")
The pseudo-code is full of errors, but the idea is that wrapInner has no clue about the signature of inner. However, it is able to inspect the signature (using, perhaps, reflect?) and creates a function that adds logic to inner and has exactly the same signature as inner. Is this possible?
What you are trying to achieve is the middleware pattern. It is commonly implemented with interfaces. You would have to manually implement the middleware function for every function you wish to annotate.
Here is an example:
package main
import (
"fmt"
"strconv"
)
type Service interface {
myFunc(a int, b string) (string, error)
}
type implService struct{}
func (s implService) myFunc(a int, b string) (string, error) {
return strconv.Itoa(a) + b, nil
}
type loggingMiddleware struct {
next Service
}
func (s loggingMiddleware) myFunc(a int, b string) (string, error) {
fmt.Println(a, b)
return s.next.myFunc(a, b)
}
func main() {
var myservice Service = &implService{}
myservice = &loggingMiddleware{
next: myservice,
}
result, err := myservice.myFunc(1, "a") // prints 1 a
fmt.Println(result, err) // prints 1a <nil>
}

Inserting custom time, Scanner and Valuer implemented — but still errs

I have a custom time format that is the result of some custom unmarshalling:
type customTime struct {
time.Time
}
I have implemented the Scanner and Valuer interface on this customTime like so:
func (ct *customTime) Scan(value interface{}) error {
ct.Time = value.(time.Time)
return nil
}
func (ct *customTime) Value() (driver.Value, error) {
return ct.Time, nil
}
But it still errs when I try to do the insert:
sql: converting Exec argument $3 type: unsupported type main.customTime, a struct
What am I missing?
Found the solution, Scanner and Valuer should be implemented on the actual value and not a pointer to the customTime
func (ct customTime) Scan(value interface{}) error {
ct.Time = value.(time.Time)
return nil
}
func (ct customTime) Value() (driver.Value, error) {
return ct.Time, nil
}

How to modify type slice inside method?

How to modify type slice inside method? I tried
http://play.golang.org/p/ul2n8mk6ye
type Test []string
func (test Test) Add(str string) {
test = append(test, str)
}
func main() {
test := Test{}
test.Add("value")
fmt.Println(len(test))//0
}
And http://play.golang.org/p/nV9IO7E5sp
type Test []string
func (test *Test) Add(str string) {
v := append(*test, str)
test = &v
}
func main() {
test := Test{}
test.Add("value")
fmt.Println(len(test))//0
}
But it does not work.
You need to use a pointer receiver, which you've tried in your second example, but you then overwrite the pointer value which defeats the purpose.
You could use
func (test *Test) Add(str string) {
v := append(*test, str)
*test = v
}
Or more clearly:
func (test *Test) Add(str string) {
*test = append(*test, str)
}

Dynamic function call in Go

I'm trying to dynamically call functions returning different types of struct.
For example, let's take the following code.
struct A {
Name string
Value int
}
struct B {
Name1 string
Name2 string
Value float
}
func doA() (A) {
// some code returning A
}
func doB() (B) {
// some code returning B
}
I would like to pass either the function doA or doB as an argument to a generic function that would execute the function and JSON-encode the result. Like the following:
func Generic(w io.Writer, fn func() (interface {}) {
result := fn()
json.NewEncoder(w).Encode(result)
}
But when I do:
Generic(w, doA)
I get the following error:
cannot use doA (type func() (A)) as type func() (interface {})
Is there a way to achieve this dynamic call?
First, let me remark that func() (interface{}) means the same thing as func() interface{}, so I'll use the shorter form.
Passing a function of type func() interface{}
You can write a generic function that takes a func() interface{} argument as long as the function that you pass to it has type func() interface{}, like this:
type A struct {
Name string
Value int
}
type B struct {
Name1 string
Name2 string
Value float64
}
func doA() interface{} {
return &A{"Cats", 10}
}
func doB() interface{} {
return &B{"Cats", "Dogs", 10.0}
}
func Generic(w io.Writer, fn func() interface{}) {
result := fn()
json.NewEncoder(w).Encode(result)
}
You can try out this code in a live playground:
http://play.golang.org/p/JJeww9zNhE
Passing a function as an argument of type interface{}
If you want to write functions doA and doB that return concretely typed values, you can pass the chosen function as an argument of type interface{}. Then you can use the reflect package to make a func() interface{} at run-time:
func Generic(w io.Writer, f interface{}) {
fnValue := reflect.ValueOf(f) // Make a concrete value.
arguments := []reflect.Value{} // Make an empty argument list.
fnResults := fnValue.Call(arguments) // Assume we have a function. Call it.
result := fnResults[0].Interface() // Get the first result as interface{}.
json.NewEncoder(w).Encode(result) // JSON-encode the result.
}
More concisely:
func Generic(w io.Writer, fn interface{}) {
result := reflect.ValueOf(fn).Call([]reflect.Value{})[0].Interface()
json.NewEncoder(w).Encode(result)
}
Complete program:
package main
import (
"encoding/json"
"io"
"os"
"reflect"
)
type A struct {
Name string
Value int
}
type B struct {
Name1 string
Name2 string
Value float64
}
func doA() *A {
return &A{"Cats", 10}
}
func doB() *B {
return &B{"Cats", "Dogs", 10.0}
}
func Generic(w io.Writer, fn interface{}) {
result := reflect.ValueOf(fn).Call([]reflect.Value{})[0].Interface()
json.NewEncoder(w).Encode(result)
}
func main() {
Generic(os.Stdout, doA)
Generic(os.Stdout, doB)
}
Live playground:
http://play.golang.org/p/9M5Gr2HDRN
Your return signature is different for these functions:
fn func() (interface {}) vs. func doA() (A) and func doB() (B)
You are getting a compiler error because you are passing a function with a different signature into your Generic function. To address this issue you can change your functions to return interface{}.
This is an example of how to do that, I am using anonymous structs and printing the return value out rather than serializing them but this applies just the same to your example:
package main
import "fmt"
func doA() interface{} {
return struct {
Name string
Value int
}{
"something",
5,
}
}
func doB() interface{} {
return struct {
Name1 string
Name2 string
Value float64
}{
"something",
"or other",
5.3,
}
}
func main() {
fmt.Println("Hello, playground", doA(), doB())
}
Experiment with this in the Go Playground: http://play.golang.org/p/orrJw2XMW8

Timestamps in Golang

Trying to get this approach to timestamps working in my application: https://gist.github.com/bsphere/8369aca6dde3e7b4392c#file-timestamp-go
Here it is:
package timestamp
import (
"fmt"
"labix.org/v2/mgo/bson"
"strconv"
"time"
)
type Timestamp time.Time
func (t *Timestamp) MarshalJSON() ([]byte, error) {
ts := time.Time(*t).Unix()
stamp := fmt.Sprint(ts)
return []byte(stamp), nil
}
func (t *Timestamp) UnmarshalJSON(b []byte) error {
ts, err := strconv.Atoi(string(b))
if err != nil {
return err
}
*t = Timestamp(time.Unix(int64(ts), 0))
return nil
}
func (t Timestamp) GetBSON() (interface{}, error) {
if time.Time(*t).IsZero() {
return nil, nil
}
return time.Time(*t), nil
}
func (t *Timestamp) SetBSON(raw bson.Raw) error {
var tm time.Time
if err := raw.Unmarshal(&tm); err != nil {
return err
}
*t = Timestamp(tm)
return nil
}
func (t *Timestamp) String() string {
return time.Time(*t).String()
}
and the article that goes with it: https://medium.com/coding-and-deploying-in-the-cloud/time-stamps-in-golang-abcaf581b72f
However, I'm getting the following error:
core/timestamp/timestamp.go:31: invalid indirect of t (type Timestamp)
core/timestamp/timestamp.go:35: invalid indirect of t (type Timestamp)
My relevant code looks like this:
import (
"github.com/path/to/timestamp"
)
type User struct {
Name string
Created_at *timestamp.Timestamp `bson:"created_at,omitempty" json:"created_at,omitempty"`
}
Can anyone see what I'm doing wrong?
Related question
I can't see how to implement this package either. Do I create a new User model something like this?
u := User{Name: "Joe Bloggs", Created_at: timestamp.Timestamp(time.Now())}
Your code has a typo. You can't dereference a non-pointer, so you need to make GetBSON a pointer receiver (or you could remove the indirects to t, since the value of t isn't changed by the method).
func (t *Timestamp) GetBSON() (interface{}, error) {
To set a *Timestamp value inline, you need to have a *time.Time to convert.
now := time.Now()
u := User{
Name: "Bob",
CreatedAt: (*Timestamp)(&now),
}
Constructor and a helper functions like New() and Now() may come in handy for this as well.
You cannot refer to an indirection of something that is not a pointer variable.
var a int = 3 // a = 3
var A *int = &a // A = 0x10436184
fmt.Println(*A == a) // true, both equals 3
fmt.Println(*&a == a) // true, both equals 3
fmt.Println(*a) // invalid indirect of a (type int)
Thus, you can not reference the address of a with *a.
Looking at where the error happens:
func (t Timestamp) GetBSON() (interface{}, error) {
// t is a variable type Timestamp, not type *Timestamp (pointer)
// so this is not possible at all, unless t is a pointer variable
// and you're trying to dereference it to get the Timestamp value
if time.Time(*t).IsZero() {
return nil, nil
}
// so is this
return time.Time(*t), nil
}

Resources