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.
Related
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.
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.
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))
encoding/base64 and encoding/hex both support nearly the same set of functions, but base64 uses a class-based encoder, whereas hex exports the methods at the top level. Is there a simple way to create a wrapper around hex so that you can work with an abstracted encoding interface? More generally, is there a way to do the equivalent of binding a method to a struct? (e.g., SomeStruct.Encode = hex.Encode)
So far, I had to define functions on a hexEncoder struct with the same signature as the hex functions. I created an interface like this:
type Encoding interface {
Decode(dst, src []byte) (n int, err error)
DecodedLen(n int) int
Encode(dst, src []byte) // base64 returns nothing, hex returns int
EncodedLen(n int) int
}
which works perfectly with base64.StdEncoding, but I wasn't clear on how to wrap the hex methods. I created an empty struct for hex:
// wrap hex encoding/decoding so that it can be used interchangeably with base64 encoding
type hexEncoder struct {}
func (h hexEncoder) Decode(dst, src []byte) (n int, err error) {
return hex.Decode(dst, src)
}
func (h hexEncoder) DecodedLen(n int) int {
return hex.DecodedLen(n)
}
func (h hexEncoder) Encode(dst, src []byte) {
hex.Encode(dst, src) // don't return the int to match Encoding
}
func (h hexEncoder) EncodedLen(n int) int {
return hex.EncodedLen(n)
}
This works, but it's a bunch of extra boiler plate (where all that really needs to be wrapped is hex.Encode). Is there a better way to do this? Ultimately, the goal is to be able to use hex and base64 interchangeably with encoding/decoding, like in something like this:
func convert(src []byte, decoder Encoding, encoder Encoding) ([]byte, error) {
temp := make([]byte, decoder.DecodedLen(len(src)))
n, err := decoder.Decode(temp, src)
if err != nil {
return temp, err
}
dst := make([]byte, encoder.EncodedLen(len(src)))
encoder.Encode(dst, temp[:n])
return dst, nil
}
No, there is no better way to implement an interface that dispatches to functions in another package, and to be honest I cannot really imagine how a better way would look like.
What you're saying in that wrapper is:
type myType struct{}
func (myType) WhenCalledLikeThis() { DoThat() }
Which seems optimal. It doesn't need any backing memory, allows slight changes in naming and return values (as you've done for Encode), and dispatches with a single call.
I am pretty new to go and I was playing with this notify package.
At first I had code that looked like this:
func doit(w http.ResponseWriter, r *http.Request) {
notify.Post("my_event", "Hello World!")
fmt.Fprint(w, "+OK")
}
I wanted to append newline to Hello World! but not in the function doit above, because that would be pretty trivial, but in the handler afterwards like this below:
func handler(w http.ResponseWriter, r *http.Request) {
myEventChan := make(chan interface{})
notify.Start("my_event", myEventChan)
data := <-myEventChan
fmt.Fprint(w, data + "\n")
}
After go run:
$ go run lp.go
# command-line-arguments
./lp.go:15: invalid operation: data + "\n" (mismatched types interface {} and string)
After a little bit of Googling I found this question on SO.
Then I updated my code to:
func handler(w http.ResponseWriter, r *http.Request) {
myEventChan := make(chan interface{})
notify.Start("my_event", myEventChan)
data := <-myEventChan
s:= data.(string) + "\n"
fmt.Fprint(w, s)
}
Is this what I was supposed to do? My compiler errors are gone so I guess that's pretty good? Is this efficient? Should you do it differently?
According to the Go specification:
For an expression x of interface type and a type T, the primary expression x.(T) asserts that x is not nil and that the value stored in x is of type T.
A "type assertion" allows you to declare an interface value contains a certain concrete type or that its concrete type satisfies another interface.
In your example, you were asserting data (type interface{}) has the concrete type string. If you are wrong, the program will panic at runtime. You do not need to worry about efficiency, checking just requires comparing two pointer values.
If you were unsure if it was a string or not, you could test using the two return syntax.
str, ok := data.(string)
If data is not a string, ok will be false. It is then common to wrap such a statement into an if statement like so:
if str, ok := data.(string); ok {
/* act on str */
} else {
/* not string */
}
Type Assertion
This is known as type assertion in golang, and it is a common practice.
Here is the explanation from a tour of go:
A type assertion provides access to an interface value's underlying concrete value.
t := i.(T)
This statement asserts that the interface value i holds the concrete type T and assigns the underlying T value to the variable t.
If i does not hold a T, the statement will trigger a panic.
To test whether an interface value holds a specific type, a type assertion can return two values: the underlying value and a boolean value that reports whether the assertion succeeded.
t, ok := i.(T)
If i holds a T, then t will be the underlying value and ok will be true.
If not, ok will be false and t will be the zero value of type T, and no panic occurs.
NOTE: value i should be interface type.
Pitfalls
Even if i is an interface type, []i is not interface type. As a result, in order to convert []i to its value type, we have to do it individually:
// var items []i
for _, item := range items {
value, ok := item.(T)
dosomethingWith(value)
}
Performance
As for performance, it can be slower than direct access to the actual value as show in this stackoverflow answer.
//an easy way:
str := fmt.Sprint(data)
As asked for by #ρяσѕρєя an explanation can be found at https://golang.org/pkg/fmt/#Sprint. Related explanations can be found at https://stackoverflow.com/a/44027953/12817546 and at https://stackoverflow.com/a/42302709/12817546. Here is #Yuanbo's answer in full.
package main
import "fmt"
func main() {
var data interface{} = 2
str := fmt.Sprint(data)
fmt.Println(str)
}
In addition to other answers, I think it's good to have a look at "type switch":
package main
import "fmt"
func printType(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("type of %v is %v\n", i, v)
// type of 21 is int
case string:
fmt.Printf("type of %v is %v\n", i, v)
// type of hello is string
default:
fmt.Printf("type of %v is %v\n", i, v)
// type of true is bool
}
}
func main() {
printType(21)
printType("hello")
printType(true)
}
I hope it helps.
More information: https://go.dev/tour/methods/16