I've read "Effective Go" and other Q&As like this: golang interface compliance compile type check , but nonetheless I can't understand properly how to use this technique.
Please, see example:
type Somether interface {
Method() bool
}
type MyType string
func (mt MyType) Method2() bool {
return true
}
func main() {
val := MyType("hello")
//here I want to get bool if my value implements Somether
_, ok := val.(Somether)
//but val must be interface, hm..what if I want explicit type?
//yes, here is another method:
var _ Iface = (*MyType)(nil)
//but it throws compile error
//it would be great if someone explain the notation above, looks weird
}
Is there any simple ways (eg without using reflection) check value if it implements an interface?
You only have to check if a value implements an interface if you don't know the value's type.
If the type is known, that check is automatically done by the compiler.
If you really want to check anyways, you can do it with the second method you gave:
var _ Somether = (*MyType)(nil)
which would error at compile time:
prog.go:23: cannot use (*MyType)(nil) (type *MyType) as type Somether in assignment:
*MyType does not implement Somether (missing Method method)
[process exited with non-zero status]
What you are doing here, is assigning a pointer of MyType type (and nil value) to a variable of type Somether, but since the variable name is _ it is disregarded.
If MyType implemented Somether, it would compile and do nothing
Following will work:
val:=MyType("hello")
var i interface{}=val
v, ok:=i.(Somether)
It is also possible to use Implements(u Type) bool method of reflect.Type in the following way:
package main
import (
"reflect"
)
type Somether interface {
Method() bool
}
type MyType string
func (mt MyType) Method() bool {
return true
}
func main() {
inter := reflect.TypeOf((*Somether)(nil)).Elem()
if reflect.TypeOf(MyType("")).Implements(inter) {
print("implements")
} else {
print("doesn't")
}
}
You can read more on that in the documentation.
You can also take Alpha's solution:
val := MyType("hello")
var i interface{} = val
v, ok := i.(Somether)
... and reduce it further:
val := MyType("hello")
v, ok := interface{}(val).(Somether)
If you're trying to test for one-off methods, you can even do something like:
val := MyType("hello")
v, ok := interface{}(val).(interface {
Method() bool
})
NOTE: Make sure you are very careful with "pointer receiver" versus "value receiver" implementations. If the implementation uses a pointer the assertion will fail when passing in a value object. If the implementation uses a value receiver, both assertions will pass.
// Implement Somether as a POINTER receiver method
func (mt *MyType) Method() bool {
return true
}
func main() {
val := MyType("hello")
v, ok := interface{}(val).(Somether)
fmt.Println(v, ok)
// Output: <nil> false
// Notice the pass by reference
v, ok := interface{}(&val).(Somether)
fmt.Println(v, ok)
// Output: 0xc000010200 true
}
versus
// Implement Somether as a VALUE receiver method
func (mt MyType) Method() bool {
return true
}
func main() {
val := MyType("hello")
v, ok := interface{}(val).(Somether)
fmt.Println(v, ok)
// Output: hello true
// Notice the pass by reference
v, ok := interface{}(&val).(Somether)
fmt.Println(v, ok)
// Output: 0xc00008e1e0 true
}
I have a solution that I use to complement a panic handler pattern
I have not exhaustively tested the code but casual testing is affirmative
I welcome any suggestions to improve or other go expert stuff
// -------------------------------------------------------------- //
// hasErrIface -
// ---------------------------------------------------------------//
func hasErrIface(v reflect.Value) (error, bool) {
// CanInterface reports whether Interface can be used without panicking
if !v.CanInterface() {
return nil, false
}
// Interface panics if the Value was obtained by accessing unexported struct fields
err, ok := v.Interface().(error)
return err, ok
}
// -------------------------------------------------------------- //
// HasErrKind
// ---------------------------------------------------------------//
func HasErrKind(r interface{}) (err error, isErr bool) {
err = nil
isErr = false
v := reflect.ValueOf(r)
switch v.Kind() {
case reflect.Struct:
errtype := reflect.TypeOf((*error)(nil)).Elem()
if v.Type().Implements(errtype) {
err, isErr = v.Interface().(error)
}
case reflect.Ptr:
err, isErr = hasErrIface(v)
case reflect.Interface:
err, isErr = hasErrIface(v)
}
return
}
// -------------------------------------------------------------- //
// EvalErrKind
// ---------------------------------------------------------------//
func EvalErrKind(r interface{}) (errval error) {
err, isErr := HasErrKind(r)
if !isErr {
errtxt := "Unknown system error - %v :\n%v"
v := reflect.ValueOf(r)
return fmt.Errorf(errtxt, v.Type(), v)
}
return err
}
// -------------------------------------------------------------- //
// PanicHandler
// ---------------------------------------------------------------//
func PanicHandler(errHandler func(error)) func() {
return func() {
var err error
if r := recover(); r != nil {
switch r.(type) {
case ApiError:
err = r.(ApiError)
default:
err = EvalErrKind(r)
}
if errHandler != nil {
errHandler(err)
}
}
}
}
It only works with Go 1.18 or higher
//implements interface
func implInter[T any](obj any) bool {
⠀ _, ok := obj.(T)
return ok
}
var obj any = "some text"
if impleInter[string](obj) {
⠀ newObj, _ := obj.(string)
}
You can also use this:
If MyType implements the Somether interface, this should compile
// use new to create a pointer to type MyType
var _ Somether = new(MyType)
var _ Somether = MyType("")
Related
I'm trying to figure out how to implement bsoncoded.Zeroer interface.
These is my straightforward struct:
type WorkContract struct {
ID primitive.ObjectID `bson:"_id,omitempty"`
Code string `bson:"code,omitempty"`
}
func (m *WorkContract) IsZero() bool {
log.Println("zero called")
return len(m.Code) == 0
}
I've tried to implement bsoncodec.Zeroer interface.
Nevertheless, this is never reached.
My repository's SaveNew method is:
func (repository *WorkContractRepository) SaveNew(ctx context.Context, workContract *model.WorkContract) (*model.WorkContract, error) {
result, err := repository.mongoCollection.InsertOne(ctx, workContract)
if err != nil {
return nil, err
}
if oid, ok := result.InsertedID.(primitive.ObjectID); ok {
modelWorkContract.ID = oid
} else {
//TODO Handle it, probably ignore it
// Not objectid.ObjectID, do what you want
}
return workContract, nil
}
I don't quite figure out what I'm doing wrong.
Any ideas?
I'm using MarshalBSONValue to marshal an inner struct field to a custom string representation.
I can't figure out how to implement the inverse operation, UnmarshalBSONValue, in order to parse the custom string representation into an inner struct.
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/bsontype"
)
type inner struct {
value string
}
func (i inner) MarshalBSONValue() (bsontype.Type, []byte, error) {
return bsontype.String, []byte(i.value), nil
}
// How to implement this?
//
// func (i *inner) UnmarshalBSONValue(t bsontype.Type, data []byte) error {
// ...
// }
type Outer struct {
Inner inner `bson:"inner"`
}
func TestMarshalBSON(t *testing.T) {
var outer1 = Outer{Inner: inner{value: "value"}}
doc, err := bson.Marshal(outer1)
assert.NoError(t, err)
fmt.Printf("%#v\n", string(doc)) // "\x11\x00\x00\x00\x02inner\x00value\x00"
var outer2 Outer
err = bson.Unmarshal(doc, &outer2) // error
assert.NoError(t, err)
assert.Equal(t, outer1, outer2)
}
I would greatly appreciate it if anyone could provide a working implementation of UnmarshalBSONValue for the example test above.
You can use bsoncore.ReadString to parse the given value.
func (i inner) MarshalBSONValue() (bsontype.Type, []byte, error) {
return bson.MarshalValue(i.value)
}
func (i *inner) UnmarshalBSONValue(t bsontype.Type, value []byte) error {
if t != bsontype.String {
return fmt.Errorf("invalid bson value type '%s'", t.String())
}
s, _, ok := bsoncore.ReadString(value)
if !ok {
return fmt.Errorf("invalid bson string value")
}
i.value = s
return nil
}
We're in the process of writing a .NET Cadence client and are a bit confused with how MutableSideEffect() is supposed to work. We've been thinking of the ID being passed as essentially a variable name and that developers should be able to update mutable values in a workflow. When we try this though, the second MutableSideEffect() call fails with this panic:
panic: adding duplicate decision DecisionType: Marker, ID: MutableSideEffect_value-1, state=Created, isDone()=false, history=[Created]
We munged the greetings workflow sample to make these calls:
package main
import (
"fmt"
"math/rand"
"time"
"go.uber.org/cadence/activity"
"go.uber.org/cadence/workflow"
"go.uber.org/zap"
)
/**
* This greetings sample workflow executes 3 activities in sequential. It gets greeting and name from 2 different activities,
* and then pass greeting and name as input to a 3rd activity to generate final greetings.
*/
// ApplicationName is the task list for this sample
const ApplicationName = "greetingsGroup"
// This is registration process where you register all your workflows
// and activity function handlers.
func init() {
workflow.Register(SampleGreetingsWorkflow)
activity.Register(getGreetingActivity)
activity.Register(getNameActivity)
activity.Register(sayGreetingActivity)
}
// SampleGreetingsWorkflow Workflow Decider.
func SampleGreetingsWorkflow(ctx workflow.Context) error {
// Get Greeting.
ao := workflow.ActivityOptions{
ScheduleToStartTimeout: time.Minute,
StartToCloseTimeout: time.Minute,
HeartbeatTimeout: time.Second * 20,
}
ctx = workflow.WithActivityOptions(ctx, ao)
logger := workflow.GetLogger(ctx)
var greetResult string
err := workflow.ExecuteActivity(ctx, getGreetingActivity).Get(ctx, &greetResult)
if err != nil {
logger.Error("Get greeting failed.", zap.Error(err))
return err
}
f := func(ctx workflow.Context) interface{} {
return rand.Intn(100)
}
e := func(a, b interface{}) bool {
if a == b {
return true
}
return false
}
var result int
sideEffectValue := workflow.MutableSideEffect(ctx, "value-1", f, e)
err = sideEffectValue.Get(&result)
if err != nil {
panic(err)
}
logger.Debug("MutableSideEffect-1", zap.Int("Value", result))
//************** THIS CALL FAILS **************
sideEffectValue = workflow.MutableSideEffect(ctx, "value-1", f, e)
err = sideEffectValue.Get(&result)
if err != nil {
panic(err)
}
logger.Debug("MutableSideEffect-2", zap.Int("Value", result))
// Get Name.
var nameResult string
err = workflow.ExecuteActivity(ctx, getNameActivity).Get(ctx, &nameResult)
if err != nil {
logger.Error("Get name failed.", zap.Error(err))
return err
}
// Say Greeting.
var sayResult string
err = workflow.ExecuteActivity(ctx, sayGreetingActivity, greetResult, nameResult).Get(ctx, &sayResult)
if err != nil {
logger.Error("Marshalling failed with error.", zap.Error(err))
return err
}
logger.Info("Workflow completed.", zap.String("Result", sayResult))
return nil
}
// Get Name Activity.
func getNameActivity() (string, error) {
return "Cadence", nil
}
// Get Greeting Activity.
func getGreetingActivity() (string, error) {
return "Hello", nil
}
// Say Greeting Activity.
func sayGreetingActivity(greeting string, name string) (string, error) {
result := fmt.Sprintf("Greeting: %s %s!\n", greeting, name)
return result, nil
}
Are we thinking about this correctly?
This is a bug in the Go client library. It happens when a MutableSideEffect with the same id is used multiple times during a single decision.
If you force a separate decision by putting workflow.Sleep(ctx, time.Second) just before the second MutableSideEffect call the problem disappears.
I filed an issue to get this fixed.
Thanks a lot for reporting!
i'm having a trouble converting my struct table to fixedDataGrid, because i need my data to be a fixedDataGrid so that i can use machine learning methods from GoLearn lib.
My struct is like this:
type dataStruct struct{
Sepal_length string
Sepal_width string
Petal_length string
Petal_width string
Species string
}
So when i get my data from my mongo db, i get them like this:
var results []dataStruct
err := col.Find(nil).All(&results)
Is there a way to convert my "results" from []dataStruct type to base.FixedDataGrid ??
CreateModel function:
func CreateModel(c echo.Context) error {
fmt.Println("====> Entry CreateModel function");
//var results []dataStruct
var Success bool = false
Db := db.MgoDb{}
Db.Init()
defer Db.Close()
col := Db.C(db.TrainingDataCollection)
var results dataStruct
if err := col.Find(nil).All(results); err != nil {
fmt.Println("ERROR WHILE GETTING THE TRAINING DATA")
} else {
//fmt.Println("Results All: ", results)
Success = true
}
fmt.Println("=============",results)
//Initialises a new KNN classifier
cls := knn.NewKnnClassifier("euclidean", "linear", 2)
//Do a training-test split
trainData, testData := base.InstancesTrainTestSplit(results, 0.55)
cls.Fit(trainData)
//Calculates the Euclidean distance and returns the most popular label
predictions, err := cls.Predict(testData)
if err != nil {
panic(err)
}
fmt.Println(predictions)
// Prints precision/recall metrics
confusionMat, err := evaluation.GetConfusionMatrix(testData, predictions)
if err != nil {
panic(fmt.Sprintf("Unable to get confusion matrix: %s", err.Error()))
}
fmt.Println(evaluation.GetSummary(confusionMat))
return c.JSON(http.StatusOK, Success)
}
Thank you in advance for your help !
Here is how i solved the issue: Actually there is a function InstancesFromMat64(row int, col int, matrix) than creates instances from a float64 matrix, and this is what i used:
func CreateModel(c echo.Context) error {
fmt.Println("====> Entry CreateModel function");
var Success bool = false
Db := db.MgoDb{}
Db.Init()
defer Db.Close()
col := Db.C(db.TrainingDataCollection)
var results dataStruct
if err := col.Find(nil).All(&results); err != nil {
fmt.Println("ERROR WHILE GETTING THE TRAINING DATA")
} else {
Success = true
}
Data := make([]float64, len(results*nbAttrs)
/**** Filling the Data var with my dataset data *****/
mat := mat64.NewDense(row,nbAttrs,Data)
inst := base.InstancesFromMat64(row,nbAttrs,mat)
//Selecting the class attribute for our instance
attrs := inst.AllAttributes()
inst.AddClassAttribute(attrs[4])
//Initialise a new KNN classifier
cls := knn.NewKnnClassifier("manhattan","linear",3)
//Training-tessting split
trainData, testData := base.InstancesTrainTestSplit(inst,0.7)
/******* Continue the Model creation ******/
I'll be glad if my answer helps someone.
Thanks a lot #mkopriva for your help !
base.FixedDataGrid is an interface, so what you need to do is to implement that interface, that is, implement all of its methods, on the type you want to use as FixedDataGrid.
Since you want to use []dataStruct, a slice of dataStructs, which is an unnamed type, as FixedDataGrid you will have to declare a new type to be able to add methods to it because you can add methods only to named types. For example something like this:
type dataStructList []dataStruct
Now, if you take a look at the documentation, you can see that the FixedDataGrid interface declares two methods RowString and Size but also embeds another interface, the base.DataGrid interface, which means you need to implement the methods declared by DataGrid as well. So, given your new dataStructList type, you can do something like this:
func (l dataStructList) RowString(int) string { /* ... */ }
func (l dataStructList) Size() (int, int) { /* ... */ }
func (l dataStructList) GetAttribute(base.Attribute) (base.AttributeSpec, error) { /* ... */ }
func (l dataStructList) AllAttributes() []base.Attribute { /* ... */ }
func (l dataStructList) AddClassAttribute(base.Attribute) error { /* ... */ }
func (l dataStructList) RemoveClassAttribute(base.Attribute) error { /* ... */ }
func (l dataStructList) AllClassAttributes() []base.Attribute { /* ... */ }
func (l dataStructList) Get(base.AttributeSpec, int) []byte { /* ... */ }
func (l dataStructList) MapOverRows([]base.AttributeSpec, func([][]byte, int) (bool, error)) error { /* ... */ }
After you've implemented the /* ... */ parts you can then start using dataStructList as a FixedDataGrid, so something like this:
var results []dataStruct
err := col.Find(nil).All(&results)
fdg := dataStructList(results) // you can use fdg as FixedDataGrid
Or
var results dataStructList // you can use results as FixedDataGrid
err := col.Find(nil).All(&results)
Update:
After you've implemented all of those methods on the dataStructList all you need is the type of the results variable inside your function:
func CreateModel(c echo.Context) error {
fmt.Println("====> Entry CreateModel function")
//var results []dataStruct
var Success bool = false
Db := db.MgoDb{}
Db.Init()
defer Db.Close()
col := Db.C(db.TrainingDataCollection)
var results dataStructList // <--- use the type that implements the interface
if err := col.Find(nil).All(&results); err != nil { // <-- pass a pointer to results
fmt.Println("ERROR WHILE GETTING THE TRAINING DATA")
} else {
//fmt.Println("Results All: ", results)
Success = true
}
fmt.Println("=============", results)
//Initialises a new KNN classifier
cls := knn.NewKnnClassifier("euclidean", "linear", 2)
//Do a training-test split
trainData, testData := base.InstancesTrainTestSplit(results, 0.55) // <-- this will work because results if of type dataStructList, which implements the base.FixedDataGrid interface.
cls.Fit(trainData)
//Calculates the Euclidean distance and returns the most popular label
predictions, err := cls.Predict(testData)
if err != nil {
panic(err)
}
fmt.Println(predictions)
// Prints precision/recall metrics
confusionMat, err := evaluation.GetConfusionMatrix(testData, predictions)
if err != nil {
panic(fmt.Sprintf("Unable to get confusion matrix: %s", err.Error()))
}
fmt.Println(evaluation.GetSummary(confusionMat))
return c.JSON(http.StatusOK, Success)
}
I have a Get() function:
func Get(url string) *Response {
res, err := http.Get(url)
if err != nil {
return &Response{}
}
// res.Body != nil when err == nil
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
log.Fatalf("ReadAll: %v", err)
}
reflect.TypeOf(body)
return &Response{sync.Mutex(),string(body), res.StatusCode}
}
as well as a Read() function:
func Read(url string, timeout time.Duration) (res *Response) {
done := make(chan bool)
go func() {
res = Get(url)
done <- true
}()
select { // As soon as either
case <-done: // done is sent on the channel or
case <-time.After(timeout): // timeout
res = &Response{"Gateway timeout\n", 504}
}
return
}
the Response type returned by the functions is defined as:
type Response struct {
Body string
StatusCode int
}
This read function makes use of the Get() function and also implements a timeout. The problem is that a data race can occur if the timeout occurs and the Get() response is written to res at the same time in Read().
I have a plan for how to solve this. It is to use Mutex. To do this, I would add a field to the Response struct:
type Response struct {
mu sync.Mutex
Body string
StatusCode int
}
so that the Response can be locked. However, I'm not sure how to fix this in the other parts of the code.
My attempt looks like this, for the Get():
func Get(url string) *Response {
res, err := http.Get(url)
if err != nil {
return &Response{}
}
// res.Body != nil when err == nil
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
log.Fatalf("ReadAll: %v", err)
}
reflect.TypeOf(body)
return &Response{sync.Mutex(),string(body), res.StatusCode} // This line is changed.
}
and for the Read():
func Read(url string, timeout time.Duration) (res *Response) {
done := make(chan bool)
res = &Response{sync.Mutex()} // this line has been added
go func() {
res = Get(url)
done <- true
}()
select {
case <-done:
case <-time.After(timeout):
res.mu.Lock()
res = &Response{sync.Mutex(), "Gateway timeout\n", 504} // And mutex was added here.
}
defer res.mu.Unlock()
return
}
This "solution" generates these errors:
./client.go:54: missing argument to conversion to sync.Mutex: sync.Mutex()
./client.go:63: missing argument to conversion to sync.Mutex: sync.Mutex()
./client.go:63: too few values in struct initializer
./client.go:73: missing argument to conversion to sync.Mutex: sync.Mutex()
./client.go:95: cannot use "Service unavailable\n" (type string) as type sync.Mutex in field value
./client.go:95: cannot use 503 (type int) as type string in field value
./client.go:95: too few values in struct initializer
What is the correct way of using Mutex in this case?
While your answer with Volker's guidance is good, you might want to consider using a non default http.Client so that you can set a Timeout on the client making the request (then you don't have to worry about handling the timeouts yourself).
I followed Volker's suggestion and used a channel to solve the problem.
func Read(url string, timeout time.Duration) (res *Response) {
done := make(chan bool) // A channel
resChan := make(chan *Response)
go func() {
resChan <- Get(url)
done <- true
}()
select {
case <-done:
res = &Response{}
case <-time.After(timeout):
res = &Response{"Gateway timeout\n", 504}
}
return
}
Now, there can be no simultaneous writes to res. It's going to be either the timeout or the returned value of Get(url).