golang: Getting string from []byte - go

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))

Related

I have a question about Go pointer usage in package bytes

I have a question about a usage of pointer in Go. The link is here: https://golang.org/pkg/bytes/#example_Buffer.
In the type Buffer section, the first example:
type Buffer struct {
// contains filtered or unexported fields
}
func main() {
var b bytes.Buffer // A Buffer needs no initialization.
b.Write([]byte("Hello "))
fmt.Fprintf(&b, "world!")
b.WriteTo(os.Stdout)
}
and then in the
func (b *Buffer) Write(p []byte) (n int, err error)
I know that the receiver of func Write is (b *Buffer) then why in the main() function, after declaring/initializing b, we can simply use b.Write() but not (&b).Write()?
Thank you!
The receiver is a pointer, and in b.Write(), b is addressable. So Write is invoked on a pointer to b, not a copy of b. If b was not addressable, then you'd have received a compile error. For instance, this would fail:
bytes.Buffer{}.Write([]byte{1})
In general: you can call methods with pointer receivers only if you can take the address of the receiver object. The compiler passes the reference, not the copy for such methods.

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.

how to explain this program to implement interface

https://play.golang.org/p/LHkVGzmC7N
look this source.
specilly this scrap:
bw := NewWriter(b)
w, ok := bw.wr.(io.ReaderFrom)
i dont understand b is bytes element,NewWrite() take a io.Writer。
and bw.wr.(io.ReaderFrom),how use is?
what's mean the ".(io.ReaderFrom)" 's function?
and
fmt.Println(w.ReadFrom(s))
w is io.write,in io/io.go the ReadFrom(s) is interface.
type ReaderFrom interface {
ReadFrom(r Reader) (n int64, err error)
}
how in this source can implement this interface?
in this source ,i cant find anywhere to implement.
It is a type assertion.
In your case it asserts that w is not nil and that the value stored in w is of interface io.ReaderFrom. ok is going to be true if it is, and false otherwise. This code doest not check ok variable because of the author's confidence it will be implementing io.ReaderFrom interface.
bytes.Buffer implements func (b *Buffer) Write(p []byte) (n int, err error), so it is of type io.Writer and can serve as parameter to func NewWriter(w io.Writer) *Writer
bytes.Buffer also implements func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error), so it is of type io.ReadFrom, which enables the call for fmt.Println(w.ReadFrom(s))
as #akond mentioned .(io.ReaderFrom) is type assertion, and the expression w, ok := bw.wr.(io.ReaderFrom) asserts that the wr field of the Writer struct is also of type io.ReaderFrom
For further reading check laws-of-reflection, it refers to similar code.

In Go, how do I pass a slice of interface to something that expects slice of a different compatible interface? [duplicate]

This question already has answers here:
Type converting slices of interfaces
(9 answers)
Closed 6 years ago.
I have two interfaces, A and B. It happens that A includes B. Finally, I have a concrete implementation of A (call it Impl), which, by definition, also implements B.
For example:
type A interface {
Close() error
Read(b []byte) (int, error)
}
type Impl struct {}
func (I Impl) Read(b []byte) (int, error) {
fmt.Println("In read!")
return 10, nil
}
func (I Impl) Close() error {
fmt.Println("I am here!")
return nil
}
Since A requires Read(), and Impl implements A, it also satisfies io.Reader.
If I try to pass individual items across functions, it works fine. But if I try slices of A to functions expecting io.Reader, it fails.
Example:
func single(r io.Reader) {
fmt.Println("in single")
}
func slice(r []io.Reader) {
fmt.Println("in slice")
}
im := &Impl{}
// works
single(im)
// FAILS!
list := []A{t}
slice(list)
If I can pass an A to single(r io.Reader), why can I not pass []A to slice(r []io.Reader), and how would I correct it?
Actual implementation at https://play.golang.org/p/QOREQJTQhD just uncomment the last two lines in main() and the error shows:
main.go:38: cannot use list (type []A) as type []io.Reader in argument to slice
I kind of asked something similar here
In Go, how can I make a generic function with slices?
Sadly, this is definitely a weakness in Go. The only way for you to go around this is to make a new slice of type []io.Reader with elements from []A

io.MultiWriter vs. golang's pass-by-value

I'd like to create a situation where everything set to a particular log.Logger is also appended to a particular variable's array of strings.
The variable's type implements the io.Writer interface so it should be easy to add that via io.MultiWriter to log.New(), but I seem to have run into an intractable problem: the io.Writer interface is fixed and it's impossible for the variable to reference itself given golang's pass-by-value.
Maybe it will make more sense with an example:
package main
import "fmt"
import "io"
import "log"
import "os"
import "strings"
var Log *log.Logger
type Job_Result struct {
Job_ID int64
// other stuff
Log_Lines []string
}
// satisfies io.Writer interface
func (jr Job_Result) Write (p []byte) (n int, err error) {
s := strings.TrimRight(string(p),"\n ")
jr.Log_Lines= append(jr.Log_Lines,s)
return len(s), nil
}
func (jr Job_Result) Dump() {
fmt.Println("\nHere is a dump of the job result log lines:")
for n, s := range jr.Log_Lines{
fmt.Printf("\tline %d: %s\n",n,s)
}
}
func main() {
// make a Job_Result
var jr Job_Result
jr.Job_ID = 123
jr.Log_Lines = make([]string,0)
// create an io.MultiWriter that points to both stdout
// and that Job_Result var
var writers io.Writer
writers = io.MultiWriter(os.Stdout,jr)
Log = log.New(writers,
"",
log.Ldate|log.Ltime|log.Lshortfile)
// send some stuff to the log
Log.Println("program starting")
Log.Println("something happened")
Log.Printf("last thing that happened, should be %drd line\n",3)
jr.Dump()
}
This is the output, which is not surprising:
2016/07/28 07:20:07 testjob.go:43: program starting
2016/07/28 07:20:07 testjob.go:44: something happened
2016/07/28 07:20:07 testjob.go:45: last thing that happened, should be 3rd line
Here is a dump of the job result log lines:
I understand the problem - Write() is getting a copy of the Job_Result variable, so it's dutifully appending and then the copy vanishes as it's local. I should pass it a pointer to the Job_Result...but I'm not the one calling Write(), it's done by the Logger, and I can't change that.
I thought this was a simple solution to capturing log output into an array (and there is other subscribe/unsubscribe stuff I didn't show), but it all comes down to this problematic io.Write() interface.
Pilot error? Bad design? Something I'm not grokking? Thanks for any advice.
redefine the write function (is now pointer receiver)
// satisfies io.Writer interface
func (jr *Job_Result) Write (p []byte) (n int, err error) {
s := strings.TrimRight(string(p),"\n ")
jr.Log_Lines= append(jr.Log_Lines,s)
return len(s), nil
}
initialize
jr := new(Job_Result) // makes a pointer.
rest stays as is. This way, *Job_Result still implements io.Writer, but doesn't lose state.
The go tutorial already said, when a method modifies the receiver, you should probably use a pointer receiver, or the changes may be lost. Working with a pointer instead of the actual object has little downside, when you want to make sure, there is exactly one object. (And yes, it technically isn't an object).

Resources