рдирдорд╕реНрдХрд╛рд░, рд╣реЗрдмреНрд░! рдореИрдВ рдЖрдкрдХреЗ рд▓рд┐рдП рдореИрдЯ рдЗрд╡рд╛рдВрд╕ рдХреЗ рд▓реЗрдЦ
"рдЧреЛ, рдЬреАрдЖрд░рдкреАрд╕реА рдФрд░ рдбреЙрдХрд░" рдХрд╛ рдЕрдиреБрд╡рд╛рдж рдкреНрд░рд╕реНрддреБрдд рдХрд░рддрд╛ рд╣реВрдВред
рдЧреЛ рдФрд░ рдбреЙрдХрд░ рдХреЛ рд╕рд╛рдЭрд╛ рдХрд░рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХрдИ рд▓реЗрдЦ рд╣реИрдВред рдРрд╕реЗ рдХрдВрдЯреЗрдирд░ рдмрдирд╛рдирд╛ рдЬреЛ рдЧреНрд░рд╛рд╣рдХреЛрдВ рдФрд░ рдЖрдкрд╕ рдореЗрдВ рдмрд╛рддрдЪреАрдд рдХрд░ рд╕рдХреЗрдВ, рдмрд╣реБрдд рдЖрд╕рд╛рди рд╣реИред рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдПрдХ рдЫреЛрдЯрд╛ рд╕рд╛ рдЙрджрд╛рд╣рд░рдг рд╣реИ рдХрд┐ рдпрд╣ рдмреБрдирд┐рдпрд╛рджреА рд╕реНрддрд░ рдкрд░ рдХреИрд╕реЗ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
рд╣рдо рдХреНрдпрд╛ рдкреИрджрд╛ рдХрд░рддреЗ рд╣реИрдВ?
рд╣рдо рдмрд╣реБрдд рд╣реА рд╕рд░рд▓ рдХреНрд▓рд╛рдЗрдВрдЯ рдФрд░ рд╕рд░реНрд╡рд░ рдмрдирд╛рдПрдВрдЧреЗ, рдПрдХ рджреВрд╕рд░реЗ рдХреЗ рд╕рд╛рде
рдЬреАрдЖрд░рдкреАрд╕реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдмрд╛рддрдЪреАрдд
рдХрд░реЗрдВрдЧреЗ ред рд╕рд░реНрд╡рд░
рдбреЙрдХрд░ рдХрдВрдЯреЗрдирд░ рдХреЗ рдЕрдВрджрд░ рд╕реНрдерд┐рдд рд╣реЛрдЧрд╛ рддрд╛рдХрд┐ рдЗрд╕реЗ рдЖрд╕рд╛рдиреА рд╕реЗ рддреИрдирд╛рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗред
рдорд╛рди рд▓реАрдЬрд┐рдП рд╣рдореЗрдВ рдПрдХ рдРрд╕реА рд╕реЗрд╡рд╛ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдЬреЛ рдХреНрд▓рд╛рдЗрдВрдЯ рд╕реЗ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдкреНрд░рд╛рдкреНрдд рдХрд░рддреА рд╣реИ рдФрд░ рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЛ рд░рд┐рд╡рд░реНрд╕ рдХреИрд░реЗрдХреНрдЯрд░ рдСрд░реНрдбрд░ рдХреЗ рд╕рд╛рде рд▓реМрдЯрд╛рддреА рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдПрдХ "рдмрд┐рд▓реНрд▓реА" рднреЗрдЬреЗрдВ рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рдПрдХ "рдЪрд╛рд▓реВ" рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВред
.proto рдлрд╝рд╛рдЗрд▓
.proto- рдлрд╛рдЗрд▓ рдпрд╣ рдмрддрд╛рддреА рд╣реИ рдХрд┐ рд╣рдорд╛рд░реА рд╕реЗрд╡рд╛ рдХрд┐рди рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдЕрдВрдЬрд╛рдо рджреЗрдЧреА рдФрд░ рдХрд┐рд╕ рдбреЗрдЯрд╛ рдХрд╛ рдЖрджрд╛рди-рдкреНрд░рджрд╛рди рдХрд░реЗрдЧреАред рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдореЗрдВ
рдкреНрд░реЛрдЯреЛ рдлреЛрд▓реНрдбрд░ рдмрдирд╛рдПрдВ, рдФрд░ рдЙрд╕рдореЗрдВ
рд░рд┐рд╡рд░реНрд╕.рдкреНрд░реЛрдЯреЛ рдлрд╛рдЗрд▓ рдХрд░реЗрдВ
syntax = "proto3"; package reverse; service Reverse { rpc Do(Request) returns (Response) {} } message Request { string message = 1; } message Response { string message = 1; }
рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдЬрд┐рд╕реЗ рд╕рд░реНрд╡рд░ рдкрд░ рджреВрд░рд╕реНрде рд░реВрдк рд╕реЗ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рдбреЗрдЯрд╛ рд▓реМрдЯрд╛рддрд╛ рд╣реИ, рдЙрд╕реЗ
рдЖрд░рдкреАрд╕реА рдХреЗ рд░реВрдк рдореЗрдВ рдЪрд┐рд╣реНрдирд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЕрдВрддрдГрдХреНрд░рд┐рдпрд╛рддреНрдордХ рдиреЛрдбреНрд╕ рдХреЗ рдмреАрдЪ рд╕реВрдЪрдирд╛рдУрдВ рдХреЗ рдЖрджрд╛рди-рдкреНрд░рджрд╛рди рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдбреЗрдЯрд╛ рд╕рдВрд░рдЪрдирд╛рдУрдВ рдХреЛ
рд╕рдВрджреЗрд╢ рдХреЗ рд░реВрдк рдореЗрдВ рдЪрд┐рд╣реНрдирд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдкреНрд░рддреНрдпреЗрдХ рд╕рдВрджреЗрд╢ рдлрд╝реАрд▓реНрдб рдХреЛ рдПрдХ рдХреНрд░рдо рд╕рдВрдЦреНрдпрд╛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рдЗрд╕ рд╕реНрдерд┐рддрд┐ рдореЗрдВ, рд╣рдорд╛рд░рд╛ рдлрд╝рдВрдХреНрд╢рди рдХреНрд▓рд╛рдЗрдВрдЯ рд╕реЗ
рдЕрдиреБрд░реЛрдз рдкреНрд░рдХрд╛рд░ рдХреЗ рд╕рдВрджреЗрд╢ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ рдФрд░
рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдкреНрд░рдХрд╛рд░ рдХреЗ рд╕рдВрджреЗрд╢ рд▓реМрдЯрд╛рддрд╛ рд╣реИред
рдПрдХ рдмрд╛рд░ рдЬрдм рд╣рдордиреЗ рдПрдХ
.proto рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдИ рд╣реИ, рддреЛ рд╣рдорд╛рд░реА рд╕реЗрд╡рд╛ рдХреА
.go рдлрд╝рд╛рдЗрд▓ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП,
рдкреНрд░реЛрдЯреЛ рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рдирд┐рдореНрди рдХрдВрд╕реЛрд▓ рдХрдорд╛рдВрдб рдЪрд▓рд╛рдПрдБ:
$ protoc -I . reverse.proto --go_out=plugins=grpc:.
рдмреЗрд╢рдХ, рдкрд╣рд▓реЗ рдЖрдкрдХреЛ
рдЬреАрдЖрд░рдкреАрд╕реА рдмрдирд╛рдиреЗ рдХреА рдЬрд░реВрд░рдд рд╣реИред
рдЙрдкрд░реЛрдХреНрдд рдХрдорд╛рдВрдб рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рд╕реЗ рдПрдХ рдирдИ
.go рдлрд╝рд╛рдЗрд▓
рдмрдиреЗрдЧреА рдЬрд┐рд╕рдореЗрдВ рдХреНрд▓рд╛рдЗрдВрдЯ, рд╕рд░реНрд╡рд░ рдФрд░ рд╕рдВрджреЗрд╢ рдмрдирд╛рдиреЗ рдХреЗ рддрд░реАрдХреЗ рд╣реИрдВ, рдЬреЛ рд╡реЗ рд╡рд┐рдирд┐рдордп рдХрд░рддреЗ рд╣реИрдВред рдпрджрд┐ рд╣рдо
рдЧреЛрдбреЛрдХ рдХрд╣рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рджреЗрдЦреЗрдВрдЧреЗ:
$ godoc . PACKAGE DOCUMENTATION package reverse import "." Package reverse is a generated protocol buffer package. It is generated from these files: reverse.proto It has these top-level messages: Request Response ....
рдЧреНрд░рд╛рд╣рдХ
рдпрд╣ рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛ рдпрджрд┐ рд╣рдорд╛рд░реЗ рдЧреНрд░рд╛рд╣рдХ рдЗрд╕ рддрд░рд╣ рдХрд╛рдо рдХрд░реЗрдВ:
reverse "this is a test" tset a si siht
рдпрд╣рд╛рдВ рд╡рд╣ рдХреЛрдб рд╣реИ рдЬреЛ
.proto рдлрд╝рд╛рдЗрд▓ рд╕реЗ рдЙрддреНрдкрдиреНрди рдбреЗрдЯрд╛ рд╕рдВрд░рдЪрдирд╛рдУрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ
gRPC рдХреНрд▓рд╛рдЗрдВрдЯ рдмрдирд╛рддрд╛ рд╣реИ:
package main import ( "context" "fmt" "os" pb "github.com/matzhouse/go-grpc/proto" "google.golang.org/grpc" "google.golang.org/grpc/grpclog" ) func main() { opts := []grpc.DialOption{ grpc.WithInsecure(), } args := os.Args conn, err := grpc.Dial("127.0.0.1:5300", opts...) if err != nil { grpclog.Fatalf("fail to dial: %v", err) } defer conn.Close() client := pb.NewReverseClient(conn) request := &pb.Request{ Message: args[1], } response, err := client.Do(context.Background(), request) if err != nil { grpclog.Fatalf("fail to dial: %v", err) } fmt.Println(response.Message) }
рд╕рд░реНрд╡рд░
рд╕рд░реНрд╡рд░ рдПрдХ рд╣реА рдЙрддреНрдкрдиреНрди
.go рдлрд╝рд╛рдЗрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдЧрд╛ред рд╣рд╛рд▓рд╛рдБрдХрд┐, рдпрд╣ рдХреЗрд╡рд▓ рд╕рд░реНрд╡рд░ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╣рдореЗрдВ рдЕрдкрдиреЗ рджрдо рдкрд░ рддрд░реНрдХ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдирд╛ рд╣реЛрдЧрд╛:
package main import ( "net" pb "github.com/matzhouse/go-grpc/proto" "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/grpclog" ) func main() { listener, err := net.Listen("tcp", ":5300") if err != nil { grpclog.Fatalf("failed to listen: %v", err) } opts := []grpc.ServerOption{} grpcServer := grpc.NewServer(opts...) pb.RegisterReverseServer(grpcServer, &server{}) grpcServer.Serve(listener) } type server struct{} func (s *server) Do(c context.Context, request *pb.Request) (response *pb.Response, err error) { n := 0
рдбрд╛рдХ рдореЗрдВ рдХрд╛рдо рдХрд░рдиреЗрд╡рд╛рд▓рд╛ рдордЬрд╝рджреВрд░
рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЖрдк рдЬрд╛рдирддреЗ рд╣реИрдВ рдХрд┐
рдбреЙрдХрдЯрд░ рдХреНрдпрд╛
рд╣реИ рдФрд░ рдЗрд╕рдХреЗ рд▓рд┐рдП рдХреНрдпрд╛ рд╣реИред рдпрд╣рд╛рдБ рд╣рдорд╛рд░рд╛
рдбреЙрдХрдлрд╛рдЗрд▓ рд╣реИ :
FROM golang:1.12 ADD . /go/src/github.com/matzhouse/go-grpc/server RUN go install github.com/matzhouse/go-grpc/server ENTRYPOINT ["/go/bin/server"] EXPOSE 5300
рдбреЙрдХрд░ рдЫрд╡рд┐ рдХреЗ рд▓рд┐рдП рд╡рд┐рдзрд╛рдирд╕рднрд╛ рдХреЛрдб рдпрд╣рд╛рдВ рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рд╣реИред рд╣рдо рдЗрд╕рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рд▓рд╛рдЗрди рджреНрд╡рд╛рд░рд╛ рдХрд░реЗрдВрдЧреЗред
FROM golang:1.12
рдЗрд╕ рдХрдорд╛рдВрдб рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рд╣рдо рдкрд╣рд▓реЗ рд╕реЗ рдмрдирд╛рдИ рдЧрдИ рдЫрд╡рд┐ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдЕрдкрдиреЗ рдЖрд╡реЗрджрди рдХреА рдПрдХ рдЫрд╡рд┐ рдмрдирд╛рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдХрд╛ рдирд╛рдо рд╣реИ
рдЧреЛрд▓рдЧрдВрдЧ ред рдпрд╣
рдЧреЛ рдореЗрдВ рд▓рд┐рдЦреЗ рдЧрдП рдкреНрд░реЛрдЧреНрд░рд╛рдо рдмрдирд╛рдиреЗ рдФрд░ рдЪрд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд╣рд▓реЗ рд╕реЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд┐рдП рдЧрдП рд╡рд╛рддрд╛рд╡рд░рдг рдХреЗ рд╕рд╛рде рдПрдХ
рдбреЙрдХрдЯрд░ рдЫрд╡рд┐ рд╣реИред
ADD . /go/src/github.com/matzhouse/go-grpc/server
рдпрд╣ рдХрдорд╛рдВрдб рд╣рдорд╛рд░реЗ рдПрдкреНрд▓реАрдХреЗрд╢рди рдХреЗ рд╕реЛрд░реНрд╕ рдХреЛрдб рдХреЛ
GOPATH / src рдХрдВрдЯреЗрдирд░ рдореЗрдВ
рдХреЙрдкреА рдХрд░рддрд╛ рд╣реИ ред
RUN go install github.com/matzhouse/go-grpc/server
рдпрд╣ рдХрдорд╛рдВрдб рд╣рдорд╛рд░реЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдХрдВрдЯреЗрдирд░ рдореЗрдВ рдХреЙрдкреА рдХрд┐рдП рдЧрдП рд╕реНрд░реЛрддреЛрдВ рд╕реЗ рдЗрдХрдЯреНрдард╛ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ
GOPATH / рдмрд┐рди рдХрдВрдЯреЗрдирд░
рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рддрд╛ рд╣реИред
ENTRYPOINT ["/go/bin/server"]
рдпрд╣ рдХрдорд╛рдВрдб рдХрдВрдЯреЗрдирд░ рдХреЛ рдПрдХ рдирд┐рд╖реНрдкрд╛рджрди рдпреЛрдЧреНрдп рдкреНрд░реЛрдЧреНрд░рд╛рдо рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рддрд╛ рд╣реИред рдЗрд╕рдореЗрдВ, рд╣рдо рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдирд┐рд╖реНрдкрд╛рджрди рдпреЛрдЧреНрдп рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрде рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдФрд░, рдпрджрд┐ рдЖрд╡рд╢реНрдпрдХ рд╣реЛ, рддреЛ рдХрдорд╛рдВрдб рд▓рд╛рдЗрди рддрд░реНрдХред
EXPOSE 5300
рдЗрд╕ рдХрдорд╛рдВрдб рдХреЗ рд╕рд╛рде, рд╣рдо рдХрдВрдЯреЗрдирд░ рдХреЛ рдмрддрд╛рддреЗ рд╣реИрдВ рдХрд┐ рдХрд┐рди рдмрдВрджрд░рдЧрд╛рд╣реЛрдВ рдХреЛ рдмрд╛рд╣рд░ рд╕реЗ рдкрд╣реБрдВрдЪрдирд╛ рдЪрд╛рд╣рд┐рдПред
рд╕рд░реНрд╡рд░ рдкреНрд░рд╛рд░рдВрдн
рд╣рдореЗрдВ рдЕрдкрдиреЗ рд╕рд░реНрд╡рд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд╕рд╛рде рдХрдВрдЯреЗрдирд░ рдХреЛ рдЪрд▓рд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
рдкрд╣рд▓реЗ рдЖрдкрдХреЛ
Dockerfile рдХреЗ рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдЫрд╡рд┐ рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:
$ sudo docker build -t matzhouse/grpc-server . Sending build context to Docker daemon 31.76 MB Step 1/5 : FROM golang ---> a0c61f0b0796 Step 2/5 : ADD . /go/src/github.com/matzhouse/go-grpc ---> 9508be6501c1 Removing intermediate container 94dc6e3a9a20 Step 3/5 : RUN go install github.com/matzhouse/go-grpc/server ---> Running in f3e0b993a420 ---> f7a0370b7f7d Removing intermediate container f3e0b993a420 Step 4/5 : ENTRYPOINT /go/bin/server ---> Running in 9c9619e45df4 ---> fb34dfe1c0ea Removing intermediate container 9c9619e45df4 Step 5/5 : EXPOSE 5300 ---> Running in 0403390af135 ---> 008e09b9aebd Removing intermediate container 0403390af135 Successfully built 008e09b9aebd
рдЕрдм рд╣рдо рдЗрд╕ рдЫрд╡рд┐ рдХреЛ рд╕реВрдЪреА рдореЗрдВ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ:
$ docker images REPOSITORY TAG IMAGE ID ... matzhouse/grpc-server latest 008e09b9aebd ...
рдмрд╣реБрдд рдмрдврд╝рд┐рдпрд╛! рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╣рдорд╛рд░реЗ рд╕рд░реНрд╡рд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреА рдПрдХ рдЫрд╡рд┐ рд╣реИ, рдЬрд┐рд╕рдХреЗ рд╕рд╛рде рдЖрдк рдирд┐рдореНрди рдХрдорд╛рдВрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЕрдкрдирд╛ рдХрдВрдЯреЗрдирд░ рд▓реЙрдиреНрдЪ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
$ docker run -it -p 5300:5300 matzhouse/grpc-server
рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рддрдерд╛рдХрдерд┐рдд
рдкреЛрд░реНрдЯ рдЕрдЧреНрд░реЗрд╖рдг ред рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдЗрд╕рдХреЗ рд▓рд┐рдП рд╣рдореЗрдВ
EXPOSE рд╕реНрдЯреЗрдЯрдореЗрдВрдЯ рдФрд░
-p рддрд░реНрдХ рджреЛрдиреЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
рдХреНрд▓рд╛рдЗрдВрдЯ рд▓реЙрдиреНрдЪ
рдХреНрд▓рд╛рдЗрдВрдЯ рдХрд╛ рдХрдВрдЯреЗрдирд░реАрдХрд░рдг рдмрдбрд╝рд╛ рд▓рд╛рдн рдирд╣реАрдВ рджреЗрдЧрд╛, рддреЛ рдЖрдЗрдП рдЗрд╕реЗ рд╕рд╛рдорд╛рдиреНрдп рддрд░реАрдХреЗ рд╕реЗ рд╢реБрд░реВ рдХрд░реЗрдВ:
$ go build -o reverse $ ./reverse "this is a test" tset a si siht
рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж!