Learn Go Documentation
website·Indexed 29 days ago
https://shibin-cli.github.io/learn-go/A comprehensive guide to the Go programming language covering core concepts such as interfaces, coding specifications, and web development with Gin. It includes detailed sections on database management using GORM (CRUD, models, and relations) and remote procedure calls using RPC, Protocol Buffers, and gRPC, including interceptors and message validation.
What's inside Learn Go
- Go uses a structural type system similar to 'duck typing' ('if it walks like a duck and quacks like a duck, it's a duck'). Interfaces in Go describe the external behavior (methods) of an object rather than its internal structure. A type implements an interface implicitly by implementing all the methods defined in that interface, without needing an explicit 'implements' keyword.
Delete records and Soft Delete mechanism
Use
Deleteto remove records. If the model includes agorm.DeletedAtfield, GORM performs a Soft Delete, marking the record as deleted by setting the timestamp instead of removing the row. Soft-deleted records are automatically excluded from normal queries.- To query soft-deleted records, use
Unscoped(). - To permanently delete a record (Hard Delete), use
Unscoped().Delete().
// Delete by primary key db.Delete(&user) db.Delete(&User{}, 10) // Batch delete with condition db.Where("email LIKE ?", "%shibin%").Delete(&Email{}) // Query including soft-deleted records db.Unscoped().Find(&users) // Permanent (Hard) delete db.Unscoped().Delete(&user)- To query soft-deleted records, use
Implement gRPC streaming patterns in Go
gRPC supports three types of streaming patterns in addition to simple unary RPCs: Server-side streaming, Client-side streaming, and Bidirectional streaming. These are defined in the.protofile using thestreamkeyword in the return type or the request parameter.syntax = "proto3"; option go_package = "./;stream"; service Stream { // Server-side streaming: Client sends one request, server sends a stream of responses rpc GetStream(StreamReqData) returns (stream StreamResData); // Client-side streaming: Client sends a stream of requests, server sends one response rpc PutStream(stream StreamReqData) returns (StreamResData); // Bidirectional streaming: Both client and server send a stream of messages rpc AllStream(stream StreamReqData) returns (stream StreamResData); } message StreamReqData { string data = 1; } message StreamResData { string data = 1; }Write Go comments and documentation
Maintain a consistent commenting style for better maintainability:
- General Style: Use Chinese or English. Use spaces to separate Chinese and English characters, as well as between English and Chinese punctuation. Keep single-line comments under 120 characters.
- Function Comments: Use block comments to describe the function, parameters, and return values.
- Structs/Interfaces: Every custom struct or interface must have a brief description on the line immediately preceding the definition in the format:
StructName, Description. - Package Comments: Include a basic introduction, creator's name, and creation date (yyyyMMdd).
/* Two numbers addition Parameters: a Addend b Augend Return: The result of addition */ func add(a, b int) int { return a + b }Implement middleware in Gin
Middleware can be applied globally usingr.Use()or to specific route groups. To stop the execution of subsequent handlers in the chain, callc.Abort(). Usec.Next()to yield control to the next handler.func authRequired() gin.HandlerFunc { return func(c *gin.Context) { token := c.GetHeader("X-Token") if token != "shibin" { c.JSON(http.StatusUnauthorized, gin.H{"msg": "invalid token"}) c.Abort() // Prevents subsequent handlers from executing return } c.Next() } } func main() { r := gin.New() r.Use(authRequired()) r.Run(":8080") }Expose Go RPC services over HTTP
To transport RPC calls over HTTP instead of raw TCP, usehttp.HandleFuncto wrap the request body and response writer into anio.ReadWriteCloser, then pass it torpc.ServeRequestusing thejsonrpccodec.// Server side http.HandleFunc("/json", func(w http.ResponseWriter, r *http.Request) { var conn io.ReadWriteCloser = struct { io.Writer io.ReadCloser }{ ReadCloser: r.Body, Writer: w, } rpc.ServeRequest(jsonrpc.NewServerCodec(conn)) }) http.ListenAndServe(":8080", nil) // Client side (Python example using requests) import requests request = {"id": 0, "params": ["body"], "method": "HelloService.Hello"} res = requests.post("http://localhost:8080/json", json=request) print(res.text)Bind and validate request data using structs
Use model binding to map request data to Go structs. Gin uses
go-playground/validatorfor validation via struct tags.- Use
json:"fieldname"for JSON binding. - Use
binding:"required"to make a field mandatory. - Use
binding:"min=x,max=y,email,len=x"for specific validation rules.
Binding Methods:
- Must Bind:
Bind,BindJSON,BindXML,BindQuery,BindYAML(automatically sets 400 error on failure). - Should Bind:
ShouldBind,ShouldBindJSON,ShouldBindXML,ShouldBindQuery,ShouldBindYAML(returns error for manual handling).
Specific Binding Types:
ShouldBindUri: For URL path parameters (usesuritag).ShouldBindQuery: For query string parameters (usesformtag).
type Signup struct { Username string `json:"username" binding:"required,min=3,max=30"` Email string `json:"email" binding:"required,email"` } r.POST("/login", func(c *gin.Context) { var user Signup if err := c.ShouldBind(&user); err != nil { c.JSON(http.StatusBadRequest, gin.H{"err": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"user": user}) })- Use
Define and implement an interface in Go
To create an interface in Go, use thetypekeyword followed by the interface name and theinterfacekeyword. The body contains the method signatures that any implementing type must provide. A concrete type (like a struct) implements the interface by defining methods with matching signatures.package main import "fmt" // Define the interface type Duck interface { Gaga() Swim() } // Define a concrete type type ToyDuck struct {} // Implement the Gaga method for ToyDuck func (td *ToyDuck) Gaga() { fmt.Println("嘎嘎...") } // Implement the Swim method for ToyDuck func (td *ToyDuck) Swim() { fmt.Println("游泳..") } func main() { // Assign a pointer to ToyDuck to the Duck interface var duck Duck = &ToyDuck{} duck.Gaga() duck.Swim() }Install gRPC and Protocol Buffers for Go
To use gRPC in Go, you need the Protocol Buffer compiler (protoc) and the Go-specific plugins for generating code.# Install protoc (Mac) brew install protoc # Install Go plugins for protobuf and gRPC go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28 go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2 # Add Go bin directory to PATH export PATH="$PATH:$(go env GOPATH)/bin"Install Go and Development Tools
To start developing with Go, download the Go language distribution from the official site or the Chinese mirror. For the IDE, common choices include JetBrains GoLand or Visual Studio Code.Go Distribution: https://golang.google.cn/dl/ IDEs: GoLand (https://www.jetbrains.com/go/) or VS Code (https://code.visualstudio.com/)
Implement a gRPC Unary Server Interceptor
Server interceptors can be used for cross-cutting concerns like authentication. You can pass a unary interceptor togrpc.NewServerusing thegrpc.UnaryInterceptoroption. The interceptor function can inspect the context (e.g., for tokens in metadata) and decide whether to proceed with the handler or return an error.func interceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { md, ok := metadata.FromIncomingContext(ctx) if !ok { return resp, status.Error(codes.Unauthenticated, "no token authentication info") } var token string if val, ok := md["token"]; ok { token = val[0] } fmt.Println("token", token) res, err := handler(ctx, req) return res, err } func main() { s := grpc.NewServer(grpc.UnaryInterceptor(interceptor)) hello.RegisterHelloServiceServer(s, &Server{}) serve, _ := net.Listen("tcp", "0.0.0.0:8080") _ = s.Serve(serve) }Install Gin web framework
Install the Gin HTTP web framework using the go get command.go get -u github.com/gin-gonic/gin