Why json.Marshal and json.Unmarshal have different signature - go

func Marshal(v interface{}) ([]byte, error)
func Unmarshal(data []byte, v interface{}) error
notice that Marshal accept an interface and return a []byte as output, while Unmarshal accept an []byte and write output directly to the input parameter data
what make the difference in design
an associate question:
I think use input parameter could save in-memory copy once(function return need a copy), every assignment in golang is a copy op, so it looks like Unmarshal can save a copy, but Marshal not.
so I'm confused...

The potential functions in symmetric pairs are:
func Marshal(v interface{}) ([]byte, error) // 1
func Unmarshal(data []byte) (interface{}, error) // 2
func Marshal(v interface{}, data *[]byte) error // 3
func Unmarshal(data []byte, v interface{}) error // 4
Functions #3 and #4 might not look symmetric because the data argument to #3 is a pointer type and the v argument to #4 is not declared to be a pointer type. They are in fact symmetric because the actual value passed to the v argument of #4 must be a pointer. The function returns an error if it is not a pointer.
Function #2 is not viable because the function does not have access to the application's result type. The function cannot unmarshal the JSON to a type if the type is not known to the function. Further, the application will need to type assert the result to use it. The standard library avoids type assertions when possible.
Function #3 is not idiomatic. Pointers to slices are rarely used in Go. I don't recall the use of any in the standard library, but I am sure someone will leave a comment here if there is a one.
We are left with the unsymmetric pair of #1 and #4:
func Marshal(v interface{}) ([]byte, error) // 1
func Unmarshal(data []byte, interface{}) error // 4

By having Marshal return a byte array, you can easily pass that to functions like bufio.Writer.Write() which takes a byte array as an argument. You might have one of those when you're writing a web service that serves JSON.
If you're using Unmarshal, then you're likely reading from JSON. By having Unmarshal take the same first argument as Marshal returns, you can get any JSON that has been output by Marshal, and pass it straight to Unmarshal.

Related

How do I serialize a map of type [string]reflect.Value?

I have been trying to work out how to get this to work, and I am stuck.
I have an object that looks like this:
type PropSet map[string]*Prop
type Prop struct {
val reflect.Value
}
and I need to generate a JSON representation of all the key value pairs that it holds. I have been reading posts on SO talking about how to marshal more mundane types, but I have not been able to figure out how to deal with the reflect.Value type. I think I should be able to do something simple like this:
func (p Prop) MarshalJSON() ([]byte, error) {
return json.Marshal(p.val.Value().Interface())
}
... but it just isn't working. Any suggestions?
Additional note: I didn't write the data structure, but the reason that I think it is using the reflect.Value for the map value is that the values that we are expecting can be ints, floats, strings etc. So this is essentially needs to do some sort of type inference with base interface to figure out the return result.
You're almost there: reflect.Value doesn't itself have a Value receiver method, nor does it need one. Changing your MarshalJSON implementation to the following works:
func (p Prop) MarshalJSON() ([]byte, error) {
return json.Marshal(p.val.Interface())
}
(i.e. dropping .Value() from the chain of function calls).
Playground link
(I don't like the use of reflect here – solutions relying on reflection are rarely clear and understandable, but it seems you can't change the upstream data structure, besides choosing not to use it.)

How to implement a generic slice appender? [duplicate]

This question already has answers here:
Appending to go lang slice using reflection
(2 answers)
Closed 8 months ago.
I'm relatively new to go. I'm trying to write a generic "appender" function. This is a simplification, but its an attempt to create a clean interface for processing some lists. Specifically, I have questions about the two errors that this generates:
package main
type GenericFunc func() *interface{}
func Append(ints interface{}, f GenericFunc) {
ints = append(ints, f())
}
func ReturnInt() *int {
i := 1
return &i
}
func main() {
var ints []*int
Append(ints, ReturnInt)
}
Playground
prog.go:5:18: first argument to append must be slice; have interface
{} prog.go:15:11: cannot use ReturnInt (type func() *int) as type
GenericFunc in argument to Append
Why can't ReturnInt be of type GenericFunc? If this doesn't work, I'm not understanding how interface{} can be used with functions at all.. can it?
How can you accept a "generic" slice and append to it using reflection? This would involve checking that GenericFunc returns the same type that the slice is, but after that appending should be possible.
The types func() *interface{} (type type of GenericFunc) and (type func() *int) (the type of ReturnInt) are different types. One returns a *interface{}. The other returns a *int. The types are not assignable to each other.
Use this function to generically append the result of a function to a slice:
func Append(sp interface{}, f interface{}) {
s := reflect.ValueOf(sp).Elem()
s.Set(reflect.Append(s, reflect.ValueOf(f).Call(nil)[0]))
}
Call it like this:
var ints []*int
Append(&ints, ReturnInt)
The function will panic if the argument is not a pointer to a slice or the function does not return a value assignable to a slice element.
playground example

Golang microservice middleware allow any type but be strict on endpoint

New to golang but what I'm trying to do is make my logging middleware generic e.g. allow any type and then call the method for the next layer.
So below us the loggingmiddleware package, where I want to be able to accept any type and print it out.
package loggingmiddleware
import (
"context"
"time"
gokitlogger "github.com/go-kit/kit/log"
)
type layer interface {
Run(context.Context, interface{}) (interface{}, error)
}
type LoggingMiddleware struct {
Logger gokitlogger.Logger
Layer layer
}
func (mw LoggingMiddleware) Run(ctx context.Context, i interface{}) (output interface{}, err error) {
defer func(begin time.Time) {
mw.Logger.Log(
"method", "name of method",
"input", i,
"output", output,
"err", err,
"took", time.Since(begin),
)
}(time.Now())
output, err = mw.Layer.Run(ctx, i)
return
}
However I want to be strict when calling the next method, if it needs to be string I want to set the type to be string rather than interface{}
In my example I want to make sure only a float64 type will be used as an argument
type mathServiceInterface interface {
Run(context.Context, float64) (float64, error)
}
type mathService struct{}
func (mathService) Run(_ context.Context, f float64) (float64, error) {
return f * f, nil
}
However with my current implementation I'm getting this error...
# github.com/jakelacey2012/blankit/blankit-ms/sqaure
./main.go:92: cannot use ms (type mathServiceInterface) as type loggingmiddleware.layer in field value:
mathServiceInterface does not implement loggingmiddleware.layer (wrong type for Run method)
have Run(context.Context, float64) (float64, error)
want Run(context.Context, interface {}) (interface {}, error)
./main.go:92: cannot use loggingmiddleware.LoggingMiddleware literal (type loggingmiddleware.LoggingMiddleware) as type mathServiceInterface in assignment:
loggingmiddleware.LoggingMiddleware does not implement mathServiceInterface (wrong type for Run method)
have Run(context.Context, interface {}) (interface {}, error)
want Run(context.Context, float64) (float64, error)
I understand the error, however I don't know whether my implementation is over complicating things because I don't know go.
I hope what I'm saying makes sense, I was unsure what to title this as so please feel free to edit it.
Also if you need more code to better explain please do let me know.
What's going to be calling these? At some point there is an actual consumer, and that consumer will (presumably, based on your code) be using an interface (either layer or an identical interface). If there's middleware, that interface will necessarily be as generic as the middleware - i.e., taking a interface{} as a parameter to Run. So making something downstream more specific (besides not compiling as you've seen) doesn't make any sense: the actual consumer won't see the more-specific interface, it will see Run(Context,interface{}) (interface{},error).
The error message says it all, for a type to implement an interface its methods must exactly match the methods the interface defines.
Sadly, this means that your system won't work as designed. You will either need to use interface{} and assert to the actual type at the end point, or you will need a separate interface (and logger function) for each type.

Is there a canonical way of passing options to a Go function?

I am writing a package that exposes this function:
func Marshal(input interface{}) ([]byte, error)
This is fine for the majority of situations, but I also want to prove another function if there are extra options:
type MarshalOptions struct {
OnlyStdClass bool
}
My first thought is to create another function:
func MarshalWithOptions(input interface{}, options MarshalOptions) ([]byte, error)
Is this the recommended way of doing this? Is there a standard naming convention for function that also provide a more specific version with options?
One common way of doing that is to declare the function as variadic so that it accepts zero or more options. Assuming Option is your option type, you would declare it like this:
func Marshal(input interface{}, options ...Option) ([]byte, error)
Then, within the function, options has the type []Option.
The function would then be called with zero or more Option arguments:
bytes, err := Marshal(input, Option1, Option2)
Or, if you have your options in a slice, you would call it like this:
bytes, err := Marshal(input, options...)
There are several references to this in the language spec (look for "variadic").
You can take a *MarshalOptions. The caller can then pass nil if they want the default behavior.
eg.
func Marshal(input interface{}, options *MarshalOptions) ([]byte, error)
I found this to the be the best balance between explicit and simplicity:
type MarshalOptions struct {
OnlyStdClass bool
}
// DefaultMarshalOptions will create a new instance of MarshalOptions with
// sensible defaults. See MarshalOptions for a full description of options.
func DefaultMarshalOptions() *MarshalOptions {
options := new(MarshalOptions)
options.OnlyStdClass = false
return options
}
func Marshal(input interface{}, options *MarshalOptions) ([]byte, error) {
// ...
}
Using the constructor pattern I can set reasonable defaults, without requiring that every option (especially if they may change) are explicitly set.
It's true that I could accept nil, but I don't because it makes it more explicit to read:
result := Marshal(123, DefaultMarshalOptions())

golang: Getting string from []byte

I'm new to go (coming from the C++ world)
I've created a new writer, which "inherits" from io.writer:
type httpWriter struct {
io.Writer
}
Next I've implemented the Write() function of the io.Writer interface:
func (w *httpWriter) Write(p []byte) (n int, err, error){...}
Then, I've redirected all output to that writer.
I'm having truble to print the actual string in the Write() implementation.
I've tried all string formatting I could find in the documentation, but none of them give me the original string as an output.
fmt.Printf("%s\n",p) \\etc..
Would appreciate assistance
Ok, two things:
You haven't "inherited" io.Writer (you simply stated that your struct contains a writer). In go, interfaces are implicit. If your struct implements Write(p []byte) (n int, err, error), it is an io.Writer and can be used with any function accepting it. Period. No need to declare anything.
As for your problem: fmt.Printf("%s\n", string(p))

Resources