Go functions dot notation - go

I want to build this:
finalResult, err := Function1(whatever type)
.Function2(whatever type)
.Function3(whatever type)
Something similar to promises in javascript but not necessarily the same concepts. Or similar to nested methods in Java. I just pretend avoid more code for the same tasks.
I don't want to do this :
result, err := new(Function1(whatever type)) //or *Function1(whatever type)
if err != nil {...}
result1, err := result.Function2(whatever type)
if err != nil {...}
finalResult, err := result1.Function3(whatever type)
if err != nil {...}
I've been trying with several options with structs and interfaces but I can't get any result.
My apology if I have a mistake in my grammar. I'm not still so good with my skill English.
Thanks,
David

I think you mean the Fluent API design pattern. You return the same Object, or struct in Go, over and over.
This pattern does not allow you to return a tuple, or multiple return types though. You can only return one object.
https://play.golang.org/p/9PceZwi1a3
package main
import (
"fmt"
)
type Object struct {
Value string
Error error
}
func (o *Object) Before(s string) *Object {
o.Value = s + o.Value
// add an error if you like
// o.Error = error.New(...)
return o
}
func (o *Object) After(s string) *Object {
// could check for errors too
if o.Error != nil {
o.Value = o.Value + s
}
return o
}
func main() {
x := Object{}
x.
Before("123").
After("456").
After("789").
Before("0")
if x.Error != nil {
// handle error
}
fmt.Println(x.Value)
}
Edit: sberry's answer had a good idea. Add an Error state on the Object struct itself which could allow u to check for errors in each func call.
Since you are new, please remember to evaluate all answers and mark the best one you believe lead you the answer.

The only way to do this would be to have each FunctionX be a method on a receiver (most likely a pointer receiver if you are mutating state) and have them each return the receiver. Like so
type someNumber struct {
n int32
}
func (s *someNumber) Add(i int32) *someNumber {
s.n += i
return s
}
func (s *someNumber) Multiply(i int32) *someNumber {
s.n *= i
return s
}
func (s *someNumber) Subtract(i int32) *someNumber {
s.n -= i
return s
}
func main() {
num := &someNumber{n: 0}
result := num.Add(5).Multiply(4).Subtract(10)
fmt.Println(result.n)
}
You could set and error on the someNumber as well, and check it at the end.
If you are looking to actually carry through the error, then you would need to do something like this.
func Function1(a int, err error) (int, error) {
if err != nil {
return a, err
}
return a, nil
}
func Function2(a int, err error) (int, error) {
if err != nil {
return a, err
}
return a*2, nil
}
func Function3(a int, err error) (int, error) {
if err != nil {
return a, err
}
return a*3, nil
}
func main() {
a, err := Function3(Function2(Function1(1, nil)))
fmt.Println(a, err)
}
But, it seems like you are looking for the type of behavior an Error Monad would bring and that does not exist in Go.

Related

Implement a struct-to-csv writer in Go

The following code attempt to implement a generic CSV writer for any simple struct. By "simple", I mean field value of the struct are of standard, simple types (int, string etc).
type (
CSV interface {
Header() []string
String([]string) (string, error)
}
CSVArray []CSV
)
func CSVOutput(w io.Writer, data CSVArray, cols []string) error {
if len(data) == 0 {
return nil
}
_, err := fmt.Fprintln(w, data[0].Header())
if err != nil {
return err
}
for _, d := range data {
str, err := d.String(cols)
if err != nil {
return err
}
_, err = fmt.Fprintln(w, str)
if err != nil {
return err
}
}
return nil
}
The problem is CSVOutput() does not actually work. e.g.:
var data []Employee //the Employee struct implements CSV interface
CSVOutput(w, data, nil)
Compilation failed: cannot use data (type []Employee) as type CSVArray in argument to CSVOutput
I understand that []CSV is not same as []Employee, as explained here, and many other resources available online.
That said, is it possible to rewrite the CSVOutput() function by using reflection:
func CSVOutput(w io.Writer, data interfac{}, cols []string) error {
sliceOfIntf = castToSlice(data) //how to do this?
if !implementedCSV(sliceOfIntf[0]) { //and how to do this?
return errors.New("not csv")
}
... ...
}
is it possible to rewrite the CSVOutput() function by using reflection
Yes
// if data is []Employee{...}, then you can do the following:
rv := reflect.ValueOf(data)
if rv.Kind() != reflect.Slice {
return fmt.Errorf("data is not slice")
}
if !rv.Type().Elem().Implements(reflect.TypeOf((*CSV)(nil)).Elem()) {
return fmt.Errorf("slice element does not implement CSV")
}
csvArr := make(CSVArray, rv.Len())
for i := 0; i < rv.Len(); i++ {
csvArr[i] = rv.Index(i).Interface().(CSV)
}
// now csvArr is CSVArray containing all the elements of data
https://go.dev/play/p/gcSOid533gx

Correct way to pass interfaces to methods

Preference: I'm new to Golang and keen to improve.
So I'm trying to learn from Dave Cheney's talk here: https://youtu.be/NwEuRO_w8HE?t=812 where we pass interfaces to methods to make code clearer and more generic.
I've implemented an example below, where I have a struct that can be outputted either to the std.out or to a file. However, I feel like it's a bit redundant just making empty structs (called "print" and "save" in ,my example), just so I can attach methods. How can I improve this?
package main
import (
"fmt"
"io"
"io/ioutil"
"log"
)
type file struct {
data string
}
func (f *file) output(w io.Writer) error {
len, err := w.Write([]byte(f.data))
if err != nil {
return err
} else {
log.Println("Bytes Out: ", len)
return nil
}
}
type print struct{}
func (print *print) Write(p []byte) (n int, err error) {
return fmt.Printf("%s\n", p)
}
type save struct{}
func (s *save) Write(p []byte) (n int, err error) {
err = ioutil.WriteFile("./dat1", []byte(p), 0644)
if err != nil {
return -1, err
}
return len(p), nil
}
func main() {
f := file{"test"}
s := save{}
p := print{}
f.output(&s)
f.output(&p)
}
Your intentions aren't clear, but to answer your original question: how to pass functions as interface values?
You could create a single adapter-like type that implements io.Writer, and when its Write() method is called, it forwards to a function of your choice. A typical example of this is the http.HandlerFunc: it's a function type that implements http.Handler, so a function can be passed when an http.Handler implementation is required.
For an io.Writer adapter, it could look like this:
type WriteFunc func(p []byte) (n int, err error)
func (w WriteFunc) Write(p []byte) (n int, err error) {
return w(p)
}
And if you have functions like these:
func PrintWrite(p []byte) (n int, err error) {
return fmt.Printf("%s\n", p)
}
func SaveWrite(p []byte) (n int, err error) {
err = ioutil.WriteFile("./dat1", []byte(p), 0644)
if err != nil {
return -1, err
}
return len(p), nil
}
You can use them as io.Writer like this:
f.output(WriteFunc(PrintWrite))
f.output(WriteFunc(SaveWrite))
Try it on the Go Playground.
You don't need print or save types here. You have a method, output, that takes an io.Writer; the whole point of that is that you can pass it any writer. Both stdout and files are writers, so everything else here is unnecessary. You could just:
func main() {
f := file{"test"}
fp,err := os.Create("./dat1")
if err != nil {
panic(err)
}
f.output(fp) // This writes to a file
f.output(os.Stdout) // This writes to stdout
}

Mocked method not working in golang while running the test cases

I am trying to mock an struct method in test cases but it is not working.
I want to mock Validate method here:
`
package main
import (
"fmt"
)
type DemoInterface interface {
Inc(int) (int, error)
Validate(int) error
}
type DemoStruct struct{}
func (l DemoStruct) Inc(num int) (int, error) {
err := l.Validate(num)
if err != nil {
return 0, err
}
num = num + 100
return num, nil
}
func (l DemoStruct) Validate(num int) error {// SOME DB LOGIC IS HERE WHICH I CAN NOT POST at Stackoverflow
if num > 100 {
return fmt.Errorf("INVALID NUM %v", num)
}
return nil
}
func main() {
s, err := DemoStruct{}.Inc(10)
if err != nil {
fmt.Println(err)
}
fmt.Println(s)
}
`
My test cases:
package main
import (
"fmt"
"testing"
)
const (
SUCCESS = "SUCCESS"
ERROR = "ERROR"
)
type MockDemoStruct struct {
DemoStruct
functionality string
}
func (m MockDemoStruct) Validate(num int) error {
switch m.functionality {
case SUCCESS:
return nil
case ERROR:
fmt.Errorf("MOCK ERROR %v", num)
}
return fmt.Errorf("MOCK ERROR %v", num)
}
func TestPath(t *testing.T) {
t.Run("ERROR", func(t *testing.T) {
ls := MockDemoStruct{DemoStruct{}, ERROR}
res, err := ls.Inc(110)
expected := fmt.Errorf("MOCK ERROR %v", 10)
if err != expected {
t.Errorf("NOT MATCH %v %v", err, expected)
//NOT MATCH INVALID NUM 110 MOCK ERROR 10
}
fmt.Println(res)
})
}
Here MockDemoStruct.Validate is not being called.
I am getting INVALID NUM 110 from Validate, but it should be MOCK ERROR 110
In this case the method Inc in the DemoStruct calls the method l.Validate where l is a DemoStruct. The reciever of that method is explicitly a DemoStruct. So the MockDemoStruct.Validate method will not be called.
Go does not have inheritance as you assumed here in your code. You can not override the method of the DemoStruct. The MockDemoStruct composes the DemoStruct. To actually test this method, I suggest passing the DemoStruct a db interface, which can be mocked in your test.
I think you also need to implement 'Inc' receiver for 'MockDemoStruct', here you trying to overuse the inheritance property of struct, looks like GO doesn't support that.
To make the method mockable we will have to use a DI(dependency injection) based code pattern.
**We can mock only those methods which are injectable**.
We have two options to introduce dependency injection in this code.
Use Delegation Design pattern with the help of interface
Introduce Monkey patching using the function as a type
Delegation using interface:
type Deligation interface {
Validate(num int) error
}
type DemoStruct struct {
delegate Deligation
}
func (DemoStruct) Validate(num int) error {
if num > 100 {
return fmt.Errorf("INVALID NUM %v", num)
}
return nil
}
func (l DemoStruct) Inc(num int) (int, error) {
err := l.delegate.Validate(num) // Call method using delegate
if err != nil {
return 0, err
}
num = num + 100
return num, nil
}
func main() {
s, err := DemoStruct{delegate: DemoStruct{}}.Inc(10) // assign delegate inside DemoStruct
if err != nil {
fmt.Println(err)
}
fmt.Println(s)
}
Using Monkey patching:
func Validate(num int) error {
if num > 100 {
return fmt.Errorf("INVALID NUM %v", num)
}
return nil
}
type DemoStruct struct {
Validate func(num int) error // function as a type
}
func (l DemoStruct) Inc(num int) (int, error) {
err := l.Validate(num)// It can be replaced in test cases.
if err != nil {
return 0, err
}
num = num + 100
return num, nil
}
func main() {
s, err := DemoStruct{Validate: Validate}.Inc(10) // assign Validate inside DemoStruct
if err != nil {
fmt.Println(err)
}
fmt.Println(s)
}
Ref: https://blog.myhro.info/2018/06/how-to-mock-golang-methods

Custom json unmarshaler return empty fields

I've implemented a custom JSON unmarshaler, but for some reason it won't return the proper value -all fields come back nil.
For example:
type test struct {
t string
}
func New(data string) (*test, error) {
return &test{t: data}, nil
}
func (t *test) UnmarshalJSON(b []byte) error {
tt, err := New(string(b))
if err != nil {
return err
}
t = tt
return nil
}
func main() {
str := `"hello"`
b := []byte(str)
t := &test{}
err := json.Unmarshal(b, t)
if err != nil {
fmt.Printf("unmarshal error occurred: %#v", err)
}
fmt.Printf("%#v", t)
}
https://play.golang.org/p/LuXkZQZHWz
The above code shows the output: &main.test{t:""}
Why doesn't it unmarshal the fields? i.e &main.test{t:"hello"}
Only when I dereference the pointers above, do I get the desired result.
i.e -
func (t *test) UnmarshalJSON(b []byte) error {
tt, err := New(string(b))
if err != nil {
return err
}
*t = *tt
return nil
}
You're assigning the local variable t, a pointer to test, to the value of the local variable tt, also a pointer to test. This has no effect on the value the original pointer t pointed to. You have to dereference the pointers to change the value it points to, rather than changing the local pointer itself:
*t = *tt

Convert map to struct

Ok, the title is a little bit misleading. What I'm after is as follows:
type MyStruct struct {
id int
name string
age int
}
func CreateFromMap(m map[string]interface{}) (MyStruct, error) {
var (
id int
name string
age int
ok bool
)
err := errors.New("Error!")
id, ok = m["id"].(int)
if !ok {
return nil, err
}
name, ok = m["name"].(string)
if !ok {
return nil, err
}
age, ok = m["age"].(int)
if !ok {
return nil, err
}
return MyStruct{id, name, age}, nil
}
Don't ask: Why I'm not using CreateFromMap(int, string, int). That object comes from somewhere else, out of my control.
It's already boring to map each key, value pair in the map to struct properties. But checking if everything is ok or not after each conversion is chaotic.
Is there an easier way of doing this other than reflection?
Let's say I assume you don't want to use reflection because you don't want to do it yourself. In this case, what about using an external package that does it for you ?
package main
import "fmt"
import "github.com/mitchellh/mapstructure"
type MyStruct struct {
Id int
Name string
Age int
}
func main() {
var m = make(map[string]interface{})
m["Id"] = 17
m["Name"] = "foo"
m["Age"] = 42
fmt.Printf("%+v\n", m)
res, err := CreateFromMap(m)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v\n", res)
}
func CreateFromMap(m map[string]interface{}) (MyStruct, error) {
var result MyStruct
err := mapstructure.Decode(m, &result)
return result, err
}
Output:
map[Age:42 Name:foo Id:17]
{Id:17 Name:foo Age:42}
It has the advantage to work whatever your structure looks like, but it uses reflection internally. Actually, I don't see any "nice" way to do what you want without using reflection and/or repetitive code for each attribute of your structure. The downside, however, is that you will have to use capitalized attributes so that they would be exported to external packages.
Edit (to answer your question in the comments):
On my opinion, if you want to specify additional rules when "creating" the structure, it should be after the decoding operation.
For instance:
func CreateFromMap(m map[string]interface{}) (MyStruct, error) {
var result MyStruct
err := mapstructure.Decode(m, &result)
if err != nil {
return result, err
}
if result.Age <= 0 {
result.Age = 0
}
if result.Name == "" {
return result, errors.New("empty name is not allowed")
}
return result, err
}
This way, you will clearly separate the "conversion" part from your structure's specific rules processing.
You can just Marshal/Unmarshal, but property names should match
func CreateFromMap(m map[string]interface{}) (MyStruct, error) {
data, _ := json.Marshal(m)
var result MyStruct
err := json.Unmarshal(data, &result)
return result, err
}

Resources