掘金 后端 ( ) • 2024-06-12 19:22

theme: channing-cyan

前言:关于我,之前是前端开发工程师,最常用的语言是 React,最近乘着 AI 的东风转职全栈。本文目标是快速掌握 Go 语言关键知识,面向有一定编程基础,想快速了解 Go 的朋友,本文借鉴了Go 入门指南

Go 语言特点:

Go 语言具有以下几个显著特点:

  1. 快速编译:编译速度媲美 Java。
  2. 高效执行:执行速度接近 C++。
  3. 易于开发:简洁的语法和强大的标准库使得开发效率很高。

Go 是一种编译型语言,通过 go build 命令编译成二进制可执行文件,这一点与 C/C++ 类似,Go 比 C++ 要慢 20%,比任何非静态和编译型语言快 2 到 10 倍。Go 语言非常适合作为服务端语言,但由于垃圾回收和自动内存分配的原因,不适合用来开发对实时性要求很高的软件。

(PS: Java 也是编译型语言,但需要在 Java 虚拟机 (JVM) 上运行。Python、Node.js 属于解释型语言,不需要编译,代码直接在解释器上执行。)

一、基本结构与流程控制。

Go 的「基本结构与流程控制」和 JavaScript 基本无异,只有一些小区别,例如

  • let 在 Go 中叫 var,定义变量时需要声明类型。
  • switch 语句中有个 fallthrough 用于强制执行下一个 case 语句。
  • 有一个 goto 但不建议使用。
  • Go 的数组(Array)是定长的,Go 切片(Slice)相当于 JavaScript 的数组。
  • ......

示例代码:基本结构与流程控制

package main

import "fmt"

func main() {
    var x int = 5
    if x > 0 {
        fmt.Println("x is positive")
    }

    for i := 0; i < 5; i++ {
        fmt.Println(i)
    }

    switch x {
    case 1:
        fmt.Println("One")
    case 5:
        fmt.Println("Five")
    default:
        fmt.Println("Other")
    }
}

二、面向对象

Go 语言虽然不支持传统的面向对象编程,但通过结构体和接口,实现了面向对象的编程思想。

结构体与方法

结构体类似于类,可以包含多个字段。方法是绑定到特定类型(包括结构体)的函数。

示例代码:结构体与方法

package main

import "fmt"

type Rect struct {
    width, height int
}

func (r Rect) area() int {
    return r.width * r.height
}

func main() {
    r := Rect{width: 10, height: 5}
    fmt.Println("Area:", r.area())
}

接口与反射

接口是一组方法签名的集合,任何实现了这些方法的类型都隐式地实现了该接口。反射是 Go 语言的一大特色,可以在运行时检查类型。

示例代码:接口与反射

package main

import (
    "fmt"
    "reflect"
)

type Shape interface {
    area() float64
}

type Circle struct {
    radius float64
}

func (c Circle) area() float64 {
    return 3.14 * c.radius * c.radius
}

func printArea(s Shape) {
    fmt.Println("Area:", s.area())
}

func main() {
    c := Circle{radius: 5}
    printArea(c)
    
    t := reflect.TypeOf(c)
    fmt.Println("Type:", t.Name())
    fmt.Println("Kind:", t.Kind())
}

三、并发

Go 原生支持并发编程,主要通过 goroutinechannel 实现。

  1. goroutine

    • 轻量级线程,由 Go 运行时管理。
    • 使用 go 关键字启动新的 goroutine。
  2. channel

    • 用于 goroutine 之间的通信。
    • 可以使用 make 函数创建 channel。

示例代码:goroutine 和 channel

func sayHello() {
    fmt.Println("Hello")
}

func main() {
    go sayHello()
    fmt.Println("World")

    ch := make(chan int)
    go func() {
        ch <- 42
    }()
    fmt.Println(<-ch)
}

四、Web 框架 - Gin

Gin 是一个高效的 Go 语言 Web 框架,非常适合快速开发 RESTful API。

示例代码:使用 Gin 构建简单的 Web 服务

package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
    r.GET("/ping", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "pong",
        })
    })
    r.Run() // 监听并在 0.0.0.0:8080 上启动服务
}

五、ORM - Gorm

Gorm 是一个功能强大的 Go 语言 ORM 库,提供了方便的数据库操作接口。

示例代码:使用 Gorm 进行数据库操作

package main

import (
    "gorm.io/driver/sqlite"
    "gorm.io/gorm"
)

type Product struct {
    gorm.Model
    Code  string
    Price uint
}

func main() {
    db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
    if err != nil {
        panic("failed to connect database")
    }

    // 自动迁移模式
    db.AutoMigrate(&Product{})

    // 创建
    db.Create(&Product{Code: "D42", Price: 100})

    // 读取
    var product Product
    db.First(&product, 1) // 根据整型主键查找
    db.First(&product, "code = ?", "D42") // 查找 code 字段值为 D42 的记录

    // 更新 - 更新产品价格为 200
    db.Model(&product).Update("Price", 200)

    // 删除 - 删除产品
    db.Delete(&product, 1)
}

六、Thrift

前后端交互基本都是 HTTP 服务,但后端服务间有更好用的通信协议,它就是RPC,可以像调用本地函数一样调用别人的服务,操作还是同步的。Thrift 是其中一种 RPC 框架。

Thrift 基础

在 Thrift 中,您需要先定义服务的接口,然后使用 Thrift 编译器生成对应语言的代码。以下是一个简单的 Thrift 示例。

示例 Thrift IDL 文件:calculator.thrift

namespace go calculator

service Calculator {
    i32 add(1: i32 num1, 2: i32 num2),
    i32 subtract(1: i32 num1, 2: i32 num2)
}

生成 Go 代码

使用 Thrift 编译器生成 Go 代码:

thrift --gen go calculator.thrift

实现 Thrift 服务端

package main

import (
    "calculator"
    "fmt"
    "git.apache.org/thrift.git/lib/go/thrift"
)

type CalculatorHandler struct{}

func (p *CalculatorHandler) Add(num1 int32, num2 int32) (r int32, err error) {
    return num1 + num2, nil
}

func (p *CalculatorHandler) Subtract(num1 int32, num2 int32) (r int32, err error) {
    return num1 - num2, nil
}

func main() {
    handler := &CalculatorHandler{}
    processor := calculator.NewCalculatorProcessor(handler)
    transport, err := thrift.NewTServerSocket(":9090")
    if err != nil {
        fmt.Println("Error:", err)
        return
    }

    server := thrift.NewTSimpleServer2(processor, transport)
    fmt.Println("Starting the simple server... on ", transport.Addr())
    server.Serve()
}

实现 Thrift 客户端

package main

import (
    "calculator"
    "fmt"
    "git.apache.org/thrift.git/lib/go/thrift"
)

func main() {
    transport, err := thrift.NewTSocket("localhost:9090")
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()
    client := calculator.NewCalculatorClientFactory(transport, protocolFactory)

    if err := transport.Open(); err != nil {
        fmt.Println("Error:", err)
        return
    }
    defer transport.Close()

    sum, err := client.Add(1, 1)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    fmt.Println("1 + 1 =", sum)
}

总结

本文介绍了 Go 语言的基本结构、流程控制、面向对象编程、并发编程、Web 开发、ORM 和 RPC 框架这些实践中最基础、最常用的知识,希望对你有用~

参考

Go 入门指南