GO语言特性介绍,看这一篇就够了!

一、前言

go语言因为其高[并发编程]优势,很多大厂后端技术栈都在切go,我们公司最近项目也用到go语言。本文介绍go语言的基本语法和核心特性,方便长期未使用go编程后可以进行快速回顾。

二、go基本语法

下表是go语言和c语言对比,语法快速自查对比表,用于快速掌握基本语法差异。

语法概念 C语言 go语言
行尾标识 ; 无,换行符为语句结束
格式化打印 printf("love you %d year", 10000); fmt.Printf("%d, %v\n", i, person)
变量 int a = 0; 显示指定类型 var a int 类型推到a := 5
变量类型 强类型 弱类型
变量赋值 a = 100; a = 10 或者 a := 10
变量空值 NULL 对象的空值(nil)
变量生命周期 栈变量: 函数内; 堆变量:全局 和C一样,全局变量和局部变量
函数定义 int func(int a) func ParseCityList(contents []byte) engine.ParserResult {} 返回值和变量类型在后面
函数体格式 {} {}
函数返回值 单个返回值,可以返回指针 可以返回多个返回值,return a, b 调用者可以用_忽略返回值。 e, _, _ := func_a()
逻辑运算符 无特殊 同C语言
分支条件 if (!ok){}; switch-case if time < 20 { x="Good day"; } 无括号
循环语句 for(i=0;i<10;i++) {} for i := 1; i <= 9; i++ {}
面向对象支持 不支持 支持,1、无继承,使用组合和ductyping来支持。2、使用interface来实现多态
类定义 struct{int a;int b;} type ParserResult struct { Requests []Request Items []interface{} } 方法不用在struct内部声明,直接定义使用绑定。func (p point) print() {}
self指针传递 传递struct指针 自动传递
构造函数定义
继承 无,手动复制struct 无,父结构组合获得方法。
线程和协程 pthread_create go func()
GC机制
泛型 不支持 (宏,C++支持template) 支持
元编程 宏,#define 支持,reflect包
函数式编程 不支持 支持,如func(){fmt.println("hello")}()
闭包 支持,static变量实现。 支持

三、go核心特性

3.1 基本特性

3.1.1 切片

go语言支持切片功能,切片是可以动态取数组任意范围的内容。

go 复制代码
numbers := []int{0,1,2,3,4,5,6,7,8} 
/* 打印子切片从索引1(包含) 到索引4(不包含)*/
fmt.Println("numbers[1:4] ==", numbers[1:4])

AI写代码go
运行
123

3.1.2 map

map是key-value的映射对,key值可以是任意类型,go语言中使用案例,可以使用make或者map[关键字]构造。

go 复制代码
// 创建一个初始容量为 10 的 Map
m := make(map[string]int, 10)

// 使用字面量创建 Map
m := map[string]int{
    "apple": 1,
    "banana": 2,
    "orange": 3,
}

// 获取键值对
v1 := m["apple"]

AI写代码go
运行
123456789101112

3.1.3 go协程

go中异步执行的协程(goroutine)非常方便,使用go语句即可异步处理,而且非常轻量化。

go 复制代码
/*起go协程,异步执行*/
go func_a()

AI写代码go
运行
12
  • 使用wg.Wait等待所有协程退出
go 复制代码
package main

import (
        "fmt"
        "sync"
)

func worker(id int, wg *sync.WaitGroup) {
        defer wg.Done() // Goroutine 完成时调用 Done()
        fmt.Printf("Worker %d started\n", id)
        fmt.Printf("Worker %d finished\n", id)
}

func main() {
        var wg sync.WaitGroup

        for i := 1; i <= 3; i++ {
                wg.Add(1) // 增加计数器
                go worker(i, &wg)
        }

        wg.Wait() // 等待所有 Goroutine 完成
        fmt.Println("All workers done")
}

AI写代码go
运行
123456789101112131415161718192021222324

3.1.4 channel

channel是用于goroutine之间通信的通道。

  1. 使用make创建一个channel,定义传递的消息结构的类型。
go 复制代码
ch := make(chan int)

AI写代码
1
  1. 消息发送接收
go 复制代码
ch <- v    // 把 v 发送到通道 ch
v := <-ch  // 从 ch 接收数据
           // 并把值赋给 v

AI写代码
123
  • select 语句

c语言中的select通常用于监听socket等fd的变化,而go中的select是用于监听所有channel的消息,并进行处理。

go 复制代码
func fibonacci(c, quit chan int) {
    x, y := 0, 1
    for {
        select {
        case c <- x:
            x, y = y, x+y
        case <-quit:
            fmt.Println("quit")
            return
        }
    }
}

AI写代码go
运行
123456789101112

3.1.5 defer延迟调用

defer延迟调用在函数退出时调用,所以一些close文件、释放锁等操作可以在open时就写上defer语句,能够有效防止泄露。

go 复制代码
func readFile(filename string) error {
    f, err := os.Open(filename)
    if err != nil {
        return err
    }
    // 确保文件在函数返回时关闭
    defer f.Close()

    // ... 处理文件 ...

    return nil
}

AI写代码go
运行
123456789101112

3.1.6 异常处理

go中没有try-catch的异常处理,和c语言一样需要显示的判断返回值ret,来做异常处理。

3.1.7 其他一些tips

1)常量定义用const ( a = 10)

2)类型系统: 类型推导 a := 10var a=10

3.2 高级特性

3.2.1 OOP编程

go语言中没有天然支持OOP,OOP(面向对象编程)的3大特性:

  • 封装
  • 继承
  • 多态

封装就是结构体,go语言当然是支持的,多态使用interface实现,而继承go语言无法天然支持,需要通过结构体组合的方式实现。

OOP特性 go实现
封装 struct
继承 使用struct组合
多态 interface+ducktyping
类方法定义

在 Go 语言中,结构体方法是指作用于特定类型变量的函数。方法与函数的区别在于,方法具有接收者,而函数没有,接收者可以是结构体类型或非结构体类型,也可以是指针类型和非指针类型。

  • 定义方法

定义方法的语法格式如下:

scss 复制代码
func (接收者变量 接收者类型) 方法名(参数列表) (返回值列表) {
// 方法体
}

AI写代码
123

例如,定义一个 point 结构体及其方法,在这个例子中,print 方法作用于 point 类型的变量 p

go 复制代码
type point struct {
X int
Y int
}


func (p point) print() {
fmt.Println(p.X, p.Y)
}

AI写代码go
运行
123456789
  • 指针接收者

使用指针接收者可以避免复制大对象,并且允许方法修改接收者的值。例如:

go 复制代码
func (p *point) ScaleBy(factor int) {
p.X *= factor
p.Y *= factor
}

AI写代码go
运行
1234
继承:struct组合

Go 语言不支持继承和方法重载,但可以通过结构体组合,通过不同的接收者类型实现方法的重写。如下例子中,Dog 结构体重写了 Animal 结构体的 Speak 方法。

go 复制代码
type Animal struct {
Name string
}

func (a *Animal) Speak() {
fmt.Println(a.Name, "says: ...")
}

type Dog struct {
Animal
}

func (d *Dog) Speak() {
fmt.Println(d.Name, "says: Woof woof!")
}

AI写代码go
运行
123456789101112131415
多态:interface

在 Go 语言中,方法是接口的实现条件之一。一个类型只有实现了接口定义的所有方法,才能被称为该接口类型的实现类。在如下这个例子中,DogCat 类型都实现了 Animal 接口中的 Speak 方法。

go 复制代码
/*定义接口*/
type Animal interface {
Speak() string
}

type Dog struct{}

func (d Dog) Speak() string {
return "Woof!"
}

type Cat struct{}

func (c Cat) Speak() string {
return "Meow!"
}

AI写代码go
运行
12345678910111213141516
  • 类型断言

检查接口值是否有实现,如果没有实现则直接panic挂起。

go 复制代码
value, ok := interfaceValue.(Type)

AI写代码
1
  • interfaceValue 是一个接口类型的变量。
  • Type 是你想要断言的类型。
  • value 是断言成功后的具体类型的值。
  • ok 是一个布尔值,表示断言是否成功。

示例:

go 复制代码
package main

import "fmt"

func main() {
    var i interface{} = "Hello, Go!"

    // 直接断言为 string 类型
    s := i.(string)
    fmt.Println("断言成功:", s)

    // 直接断言为 int 类型(会引发 panic)
    n := i.(int)
    fmt.Println("断言成功:", n)
}

AI写代码go
运行
123456789101112131415

3.2.2 泛型

泛型是 Go 语言在 1.18 版本中引入的重要特性,泛型有如下概念:

概念 作用 示例
类型参数 在函数或类型名后声明,表示待定的类型。 [T any]
类型约束 定义类型参数必须满足的条件(如支持的操作符或方法)。 int,float64,comparable,constraints.Ordered,any
any 约束类型参数为任何类型。 [T any]
comparable 约束类型参数为可比较的类型。 [K comparable]

泛型的例子:

css 复制代码
// 一个函数处理多种类型
func Max[T comparable](a, b T) T {
    if a > b {
        return a
    }
    return b
}

AI写代码
1234567
  • 联合约束

除了基础的约束条件,还可以支持使用联合体的约束,如下是约束传进来的类型只能是数字。

go 复制代码
// 数字类型约束
type Number interface {
    int | int8 | int16 | int32 | int64 | 
    uint | uint8 | uint16 | uint32 | uint64 | 
    float32 | float64
}

func Add[T Number](a, b T) T {
    return a + b
}

// 使用示例
fmt.Println(Add(10, 20))        // 输出: 30
fmt.Println(Add(3.14, 2.71))    // 输出: 5.85

AI写代码go
运行
1234567891011121314
  • 结构体类型的泛型
go 复制代码
// 泛型栈实现
type Stack[T any] struct {
    elements []T
}

// 入栈
func (s *Stack[T]) Push(value T) {
    s.elements = append(s.elements, value)
}

// 出栈
func (s *Stack[T]) Pop() (T, bool) {
    if len(s.elements) == 0 {
        var zero T
        return zero, false
    }
    
    lastIndex := len(s.elements) - 1
    value := s.elements[lastIndex]
    s.elements = s.elements[:lastIndex]
    return value, true
}

// 查看栈顶元素
func (s *Stack[T]) Peek() (T, bool) {
    if len(s.elements) == 0 {
        var zero T
        return zero, false
    }
    return s.elements[len(s.elements)-1], true
}

// 判断栈是否为空
func (s *Stack[T]) IsEmpty() bool {
    return len(s.elements) == 0
}

// 使用示例
func main() {
    // 整数栈
    intStack := Stack[int]{}
    intStack.Push(1)
    intStack.Push(2)
    intStack.Push(3)
    
    fmt.Println(intStack.Pop())  // 输出: 3 true
    
    // 字符串栈
    stringStack := Stack[string]{}
    stringStack.Push("hello")
    stringStack.Push("world")
    
    fmt.Println(stringStack.Pop())  // 输出: world true
}

AI写代码go
运行
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354

3.2.3 函数式编程

go语言天生支持函数是编程,函数是一等公民,常见的如下匿名函数,异步执行:

go 复制代码
go  func(){
fmt.println("hello word")
}()

AI写代码go
运行
123

3.2.4 闭包

go中支持闭包,闭包为介于结构体和函数之间的对象,为函数增加context,轻量化结构,通常有2个作用:静态变量,装饰函数,比如如下代码:

go 复制代码
package main

import (
	"fmt"
)

//闭包1:静态变量
func gongzi_calc(base int) func(int) int {
	base_gongzi := base
	return func(a int) int {
		return base_gongzi + a
	}
}

//闭包2:装饰函数
// 闭包相当于函数试编程,函数构造器
// 有对象的特征,有静态变量
func eat_fan(preDo func()) func(int) {
	preFunc := preDo
	return func(a int) {
		preFunc()
		fmt.Printf("i eat a %d rice!\n", a)
	}
}

func shuaya() {
	fmt.Println("shuaya ing")
}

func xilian() {
	fmt.Println("xilian ing")
}
func main() {
	hr_gongzi_calc := gongzi_calc(3500)
	engine_gongzi_calc := gongzi_calc(5000)

	liming_gongzi := hr_gongzi_calc(1500)
	fmt.Println("liming_gongzi:", liming_gongzi)
	zhangsan_gongzi := hr_gongzi_calc(3000)
	fmt.Println("zhangsan_gongzi:", zhangsan_gongzi)

	wangwu_gongzi := engine_gongzi_calc(2300)
	fmt.Println("wangwu_gongzi:", wangwu_gongzi)

	xtt_eat_fun := eat_fan(shuaya)
	zfj_eat_fun := eat_fan(xilian)

	xtt_eat_fun(10)
	zfj_eat_fun(2)
	return
}

AI写代码go
运行
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051

3.2.5 元编程

元编程是编写能够操作自身或其他程序结构的程序 ,比如动态处理结构体字段、生成数据库语句、构建路由表、序列化等。Go 虽然是静态语言,但通过 reflect 包可实现一定程度的元编程能力。

  • 常见元编程场景
场景 示例
自动绑定结构体字段 表单/JSON 转结构体
结构体转 Map 通用数据库 ORM
动态方法调用 插件、RPC
自动生成 SQL 语句 GORM、xorm 等 ORM 实现基础
参数注解校验 类似 Java 中的注解

比如使用反射+interface构建通用函数:

go 复制代码
func SetField(obj interface{}, fieldName string, value interface{}) error {
    v := reflect.ValueOf(obj).Elem()
    f := v.FieldByName(fieldName)
    if !f.IsValid() || !f.CanSet() {
        return fmt.Errorf("field not found or not settable")
    }
    val := reflect.ValueOf(value)
    if f.Type() != val.Type() {
        return fmt.Errorf("type mismatch")
    }
    f.Set(val)
    return nil
}

AI写代码go
运行
相关推荐
掘金泥石流1 小时前
分享下我创业烧了 几十万的 AI Coding 经验
前端·javascript·后端
武藤一雄2 小时前
C#:Linq大赏
windows·后端·microsoft·c#·.net·.netcore·linq
Andy工程师2 小时前
Spring Boot 按照以下顺序加载配置(后面的会覆盖前面的):
java·spring boot·后端
繁星蓝雨2 小时前
小试Spring boot项目程序(进行get、post方法、打包运行)——————附带详细代码与示例
java·spring boot·后端
山枕檀痕2 小时前
Spring Boot中LocalDateTime接收“yyyy-MM-dd HH:mm:ss“格式参数的最佳实践
java·spring boot·后端
Java水解2 小时前
【Spring Boot 单元测试教程】从环境搭建到代码验证的完整实践
后端·spring
Lear2 小时前
【JavaSE】动态代理技术详解与案例实战
后端
shark_chili2 小时前
深入剖析Java并发编程中的死锁问题
后端
开心就好20253 小时前
iOS 压力测试的工程化体系 构建多工具协同的极限稳定性验证方案
后端