二、Go语言语法基础

43 阅读29分钟

一,注释

单行注释: 语法:

// 单行注释

多行注释: 语法:

/* 多行注释 */

二,标识符

在编程语言中,标识符用于标识目的。换句话说,标识符是程序组件的用户定义名称。在Go语言中,标识符可以是变量名称,函数名称,常量,语句标签,包名称或类型。

**定义标识符的规则:**有一些定义有效的Go标识符的有效规则。应该遵守这些规则,否则,我们将得到一个编译时错误。

  • 标识符的名称必须以字母下划线(_)开头。并且名称中可能包含字母“ a-z”或“ A-Z”或数字0-9,以及字符“ _”。
  • 标识符的名称不能以数字开头
  • 标识符的名称区分大小写
  • 关键字不能用作标识符名称。
  • 标识符名称的长度没有限制,但是建议仅使用4到15个字母的最佳长度。

例:

// 有效的标识符:
_geeks23
geeks
gek23sd
Geeks
geeKs
geeks_geeks

// 无效的标识符:
212geeks
if
default

注意:

  • 在Go语言中,有一些预定义的标识符可用于常量,类型和函数。这些名称不是保留的,可以在声明中使用它们。以下是预定义标识符列表:

    常量:
    true, false, iota, nil
    
    类型:
    int, int8, int16, int32, int64, uint,
    uint8, uint16, uint32, uint64, uintptr,
    float32, float64, complex128, complex64,
    bool, byte, rune, string, error
    
    函数:
    make, len, cap, new, append, copy, close, 
    delete, complex, real, imag, panic, recover
    
  • 下划线字符(_)表示的标识符称为空白标识符。它用作匿名占位符而不是常规标识符,并且在声明,操作数和赋值中具有特殊含义。

  • 被允许从另一个包访问它的标识符称为导出标识符。导出的标识符是符合以下条件的那些标识符:

    • 导出的标识符名称的第一个字符应为Unicode大写字母
    • 标识符应在包块中声明,或者是变量名,或者是方法名。
  • 标识符的唯一性意味着标识符与程序或程序包中可用的另一组标识符是唯一的,并且不会导出。

三,关键字

关键字或保留字是用于某些内部过程或表示某些预定义动作的语言中的字。因此,不允许将这些单词用作标识符。这样做会导致编译时错误。

Go语言中共有25个关键字,如下所示:

breakcasechanconstcontinue
defaultdeferelsefallthroughfor
funcgogotoifimport
interfacemappackagerangereturn
selectstructswitchtypevar

示例

//Go程序举例说明
//使用关键字
//这里package关键字用于
//在程序中包含主包
package main 
  
// import关键字是用来
//导入“fmt”到您的包中
import "fmt"
  
// func用于
//创建函数
func main() { 
  
  //这里,使用var关键字,创建变量
  //Pname,Lname和Cname是有效的标识符
    var Pname = "name" 
    var Lname = "Go 语言" 
    var Cname = "关键字"
      
    fmt.Printf("PName: %s", Pname) 
    fmt.Printf("\n语言名称: %s", Lname) 
    fmt.Printf("\n章节名称: %s", Cname) 
  
}

输出:

PName: name
语言名称: Go 语言
章节名称: 关键字

四,数据类型

在Go语言中,数据类型分为以下四类:

  1. **基本类型:**数字,字符串和布尔值属于此类别。
  2. **聚合类型:**数组和结构属于此类别。
  3. **引用类型:**指针,切片,map集合,函数和Channel属于此类别。
  4. 接口类型

在这里,我们将讨论Go语言的基本数据类型。在基本数据类型被进一步划分为三个子类别分别是:

  • Numbers
  • Booleans
  • Strings

4.1 Numbers

在Go语言中,数字分为三个子类别:

  • 整数:在Go语言中,有符号无符号整数都可以使用四种不同的大小,如下表所示。有符号的整数由int表示,而无符号的整数用uint表示。

    数据类型描述
    int88位有符号整数
    int1616位有符号整数
    int3232位有符号整数
    int6464位有符号整数
    uint88位无符号整数
    uint1616位无符号整数
    uint3232位无符号整数
    uint6464位无符号整数
    intint 的位宽(占用的内存大小)取决于操作系统和 CPU 架构32 位系统int32 位64 位系统int64 位
    uintuint 的位宽(占用的内存大小)取决于操作系统和 CPU 架构32 位系统uint32 位64 位系统uint64 位
    rune它是int32的同义词,也表示Unicode代码点。
    byte它是int8的同义词。
    uintptr它是无符号整数类型。它的宽度未定义,但是可以容纳指针值的所有位。

    在大多数场景下(例如循环计数器、数组索引),推荐使用 int 而非固定位宽的整数类型(如 int32int64),因为:

    • Go 的标准库(如 len() 函数)返回 int 类型。
    • 更符合代码的自然表达。

    示例

    // 使用整数 
    package main  
    import "fmt"
             
    func main() { 
        // 使用8位无符号整型
        var X uint8 = 225 
        fmt.Println(X+1, X) 
          
        // 使用16位有符号整型
        var Y int16 = 32767 
        fmt.Println(Y+2, Y-2)  
    }
    

    输出:

    226 225
    -32767 32765
    
  • 浮点数:在Go语言,浮点数被分成2类如示于下表:

    数据类型描述
    float3232位IEEE 754浮点数
    float6464位IEEE 754浮点数

    示例

    // 浮点数的使用 
    package main  
    import "fmt"
             
    func main() { 
        a := 20.45 
        b := 34.89 
          
        //两个浮点数相减
        c := b-a 
          
        //显示结果 
        fmt.Printf("结果: %f", c) 
          
        //显示c变量的类型
        fmt.Printf("\nc的类型是 : %T", c)   
    }
    

    输出:

    结果: 14.440000
    c的类型是: float64
    
  • **复数:**将复数分为两部分,如下表所示。float32和float64也是这些复数的一部分。内建函数从它的虚部和实部创建一个复数,内建虚部和实部函数提取这些部分。

    数据类型描述
    complex64包含float32作为实数虚数分量的复数。
    complex128包含float64作为实数虚数分量的复数。

    示例

    //复数的使用 
    package main 
    import "fmt"
      
    func main() { 
          
       var a complex128 = complex(6, 2) 
       var b complex64 = complex(9, 2) 
       fmt.Println(a) 
       fmt.Println(b) 
         
       //显示类型 
      fmt.Printf("a的类型是 %T 以及"+ "b的类型是 %T", a, b) 
    }
    

    输出:

    (6+2i)
    (9+2i)
    a的类型是 complex128 以及b的类型是 complex64
    

4.2 Booleans

布尔数据类型仅表示true或false。布尔类型的值不会隐式或显式转换为任何其他类型。

示例

//布尔值的使用
package main

import "fmt"

func main() {

    //变量
    str1 := "cainiaojc"
    str2 := "cainiaojc"
    str3 := "cainiaojc"
    result1 := str1 == str2
    result2 := str1 == str3

    //打印结果
    fmt.Println(result1)
    fmt.Println(result2)

    //显示result1和result2的类型
    fmt.Printf("result1 的类型是 %T , "+"result2的类型是 %T", result1, result2)

}

输出:

true
true
result1 的类型是 bool , result2的类型是 bool

4.3 Strings

字符串数据类型表示Unicode代码点的序列。换句话说,我们可以说一个字符串是不可变字节的序列,这意味着一旦创建了一个字符串,您就无法更改该字符串。字符串可以包含任意数据,包括以人类可读形式包含零值的字节。

示例

//使用字符串
package main 
import "fmt"
  
func main() { 
      
    //用于存储字符串的str变量
   str := "cainiaojc"
     
   //显示字符串的长度
   fmt.Printf("字符串的长度:%d", len(str)) 
     
   //显示字符串 
   fmt.Printf("\n字符串是: %s", str) 
     
   // 显示str变量的类型
   fmt.Printf("\nstr的类型是: %T", str) 
}

输出:

字符串的长度:5
字符串是: cainiaojc
str的类型是: string

五,变量

变量是程序运行时可以修改的数据存储单元。Go的变量设计强调类型安全和简洁性。

变量命名规则:

变量名称必须以字母或下划线(_)开头。并且名称中可能包含字母“ a-z”或“ A-Z”或数字0-9,以及字符“ _”。

Geeks, geeks, _geeks23  //合法变量
123Geeks, 23geeks      // 非法变量

变量名称不应以数字开头。

234geeks  //非法变量

变量名称区分大小写。

geeks 和Geeks 是两个不同的变量

关键字不允许用作变量名。

变量名称的长度没有限制,但是建议仅使用4到15个字母的最佳长度。

5.1 声明变量

5.1.1 显式声明

这是最基础的声明方式,支持全局和局部变量,可显式指定类型或由编译器推断。

单变量声明

  • 语法var <变量名> [类型] [= 初始值]
  • 特点
    • 若未指定类型,必须初始化(编译器推断类型)。
    • 若未初始化,变量将被赋予零值(Zero Value)。

示例

// 全局变量(包内可见)
var globalInt int          // 默认值0
var globalStr = "Hello"    // 类型推断为string

func main() {
    var a int              // 局部变量,默认0
    var b string = "World" // 显式类型
    var c = 3.14           // 推断为float64
}

多变量批量声明

  • 语法:使用 var() 块或逗号分隔,可混合不同类型。

示例

var (
    name   = "Alice"
    age    = 30        // 推断为int
    isStudent bool     // 默认false(未初始化)
)

var x, y, z int = 1, 2, 3 // 同一类型多变量
var i, j = 42, "data"     // 混合类型推断

5.1.2 短变量声明

在函数内部快速声明并初始化变量,不可用于全局变量

语法<变量名> := <值>

  • 特点
    • 必须初始化,且至少有一个新变量(避免重复声明)。
    • 类型由右侧表达式自动推断。
    • 常用于局部变量或条件/循环语句中。

示例

func main() {
    a := 42                   // 推断为int
    b, s := 3.14, "Golang"    // 混合类型
    // 错误示例:无新变量时不可重复声明
    // a := 100 

    // 正确示例:至少一个新变量
    c, a := true, 100         // a被重新赋值
}

适用场景

  • 函数内局部变量。
  • ifforswitch 等代码块中临时变量:
if n := getUserCount(); n > 0 {
    fmt.Println("Users exist:", n)
}

5.1.3 匿名变量

用于忽略某个值(如函数返回的多余值),不占用命名空间,无内存分配。

语法_ = <表达式>

示例

func getData() (int, string) {
    return 404, "Not Found"
}

func main() {
    code, _ := getData() // 忽略字符串值
    fmt.Println("Status code:", code)
}

5.2 变量重声明

同一作用域内,不允许重复声明同名变量。但在以下两种情况下允许:

  1. 短声明中至少有一个新变量

    a := 10
    a, b := 20, "new" // 允许:a被赋值,b是新变量
    
  2. 子作用域隐藏(Shadowing)

    var x = 100
    func main() {
        x := "shadow" // 内部作用域的x覆盖外部的x
        fmt.Println(x) // 输出 "shadow"
    }
    

5.3 默认零值

未显式初始化的变量会被赋予类型对应的默认值:

类型零值
数值类型0
字符串""(空字符串)
布尔类型false
指针/接口nil
切片/映射/通道nil(未初始化)

5.4 变量作用域

Golang变量的范围规则可以分为两类,具体取决于声明变量的位置:

  • 局部变量(在块或函数内部声明)
  • 全局变量(在块或函数外部声明)

5.4.1 局部变量

在函数或块中声明的变量称为局部变量。这些不能在函数或块之外访问。

  • 这些变量也可以在函数内的for,while语句等内部声明。
  • 但是,这些变量可以由函数内的嵌套代码块访问。
  • 这些变量也称为块变量
  • 如果在同一作用域中用相同的名称声明两次这些变量,则会出现编译时错误。
  • 函数执行结束后,这些变量将不存在。
  • 在循环外声明的变量也可以在嵌套循环内访问。这意味着方法和所有循环都可以访问全局变量。局部变量可被循环访问,并在该函数内执行函数。
  • 在循环体内声明的变量对循环体外不可见。

示例

//局部变量
package main
import "fmt"

//主函数
func main() {

    //从这里开始主函数的局部作用域
    //主函数内的局部变量
    var myvariable1, myvariable2 int = 69, 145

    // 显示变量的值
    fmt.Printf("myvariable1 变量的值 : %d\n", myvariable1)

    fmt.Printf("myvariable2 变量的值 : %d\n", myvariable2)

} // 此处主要函数的局部作用域结束

5.4.2 全局变量

在函数或块之外定义的变量称为全局变量。

  • 这些在程序的整个生命周期中都可用
  • 这些在所有函数或块之外的程序顶部声明。
  • 这些可以从程序的任何部分进行访问。

示例

//全局变量
package main
import "fmt"

// 全局变量声明
var myvariable1 int = 100

func main() {

    // 主函数内部的局部变量
    var myvariable2 int = 200

    //显示全局变量
    fmt.Printf("全局变量 myvariable1 的值是 : %d\n", myvariable1)

    //显示局部变量
    fmt.Printf("局部变量 myvariable2 的值是 : %d\n", myvariable2)

    //调用函数
    display()

}

func display() {
    // 显示全局变量
    fmt.Printf("全局变量 myvariable1 的值是 : %d\n", myvariable1)

}

5.4.3 优先级

如果函数中存在与全局变量同名的局部变量,将会发生什么情况?

答案很简单,即编译器将优先选择局部变量。通常,当定义了两个具有相同名称的变量时,编译器会产生编译时错误。但是,如果变量在不同的范围内定义,则编译器会允许它。只要定义了与全局变量同名的局部变量,编译器就会优先考虑该局部变量。

示例:在下面的程序中,由于myvariable1的值为200,这在函数main中给出。因此,可以说局部变量比全局变量具有更高的优先级。

示例

//Go程序显示编译器的优先级
//全局变量上的局部变量
package main
import "fmt"

//全局变量声明
var myvariable1 int = 100

func main() {

    //主函数内的局部变量
    //与全局变量相同
    var myvariable1 int = 200
    // 显示
    fmt.Printf("变量 myvariable1 的值是 : %d\n", myvariable1)
}

输出:

变量 myvariable1 的值是 : 200

5.5 类型转换

当我们将一种数据类型的值分配给另一种数据类型时,就会发生类型转换。诸如C / C ++,Java之类的静态类型语言提供了对隐式类型转换的支持,但是Golang有所不同,因为即使数据类型兼容,它也不支持自动类型转换或隐式类型转换。原因是Golang的强类型系统不允许这样做。对于类型转换,必须执行显式转换。

类型转换语法:

var cainiaojc1 int = 845

// 显式类型转换
var cainiaojc2 float64 = float64(cainiaojc$1)
var cainiaojc3 int64 = int64(cainiaojc$1)
var cainiaojc4 uint = uint(cainiaojc$1)

示例

//计算平均值
package main
import "fmt"

func main() {

    var totalsum int = 446
    var number int = 23
    var avg float32

    // 显式类型转换
    avg = float32(totalsum) / float32(number)

    // 显示结果
    fmt.Printf("平均值 = %f\n", avg)
}

输出:

平均值 = 19.391304

注意:由于Golang具有强大的类型系统,因此不允许在表达式中混合使用数字类型(例如加,减,乘,除等),并且不允许在两个混合类型之间执行赋值类型。

var cainiaojc1 int64 = 875

//它会在编译时抛出错误给我们
//因为正在执行混合类型,例如把int64作为int类型
var cainiaojc2 int = cainiaojc1

var cainiaojc3 int = 100
//它抛出编译时错误
//这是无效操作
//因为类型是混合的 int64 和 int 相加
var addition = cainiaojc1 + cainiaojc3

六,常量

在Go语言中,常量(Constants)是编译期确定且不可变的值,支持灵活的类型推断和枚举生成

6.1 常量的基本声明

语法:使用 const 关键字,必须声明时初始化

const Pi = 3.1415          // 无类型浮点常量
const MaxUsers int = 1000  // 有类型常量(int)

批量声明:使用 const() 块,支持多行定义。

const (
    StatusOK    = 200
    StatusError = 500
)

6.2 常量的核心特性

无类型常量(Untyped Constants)

  • 无类型常量没有明确的类型,根据上下文自动推断。
    const n = 42          // 无类型整数
    var a int = n        // 转换为 int
    var b float64 = n    // 转换为 float64
    
  • 优势:支持高精度计算(如大整数运算)和灵活的类型适配。

有类型常量(Typed Constants)

  • 显式指定类型,需严格匹配赋值目标类型。
    const Version int = 1
    var x int = Version  // 正确
    var y float64 = Version // 错误!需显式转换
    

6.3 iota 生成枚举常量

iota 是Go的常量计数器,从0开始,每新增一行常量声明自动递增。

基本用法

const (
    A = iota    // 0
    B            // 1
    C            // 2
)

结合表达式

利用 iota 生成复杂常量(如位移、公式):

const (
    KB = 1 << (10 * iota)  // 1 << 0 = 1
    MB                       // 1 << 10 = 1024
    GB                       // 1 << 20 = 1048576
)

跳过值或重置

  • 跳过值:使用 _ 占位符。
  • 重置计数:在 const() 块中重新开始。
const (
    X = iota    // 0
    Y            // 1
    _            // 跳过2
    Z            // 3
)

// 新const块重置iota
const (
    NewA = iota  // 0
    NewB          // 1
)

6.4 常量的作用域与可见性

全局常量:在函数外声明,包内可见;首字母大写可被其他包导入。

局部常量:在函数或代码块内声明,仅作用域内有效。

package main

const GlobalConst = "I'm global"  // 可导出(首字母大写)

func main() {
    const localConst = 100       // 仅main函数内有效
}

6.5 常量与变量的区别

特性常量变量
可变性不可修改可修改
声明方式constvar:=
类型要求可无类型(灵活)必须显式或推断类型
初始化时机必须声明时初始化可先声明后赋值
内存分配编译期直接替换(无内存占用)运行时分配内存

6.6 常量的编译期约束

  • 常量值必须是编译期可确定的表达式,例如:
    • 字面量(如 42, "hello"
    • 其他常量
    • 内置函数(如 len("abc")
  • 非法示例:无法使用运行时结果。
    const Invalid = fmt.Sprintf("data") // 错误!无法编译
    

七,运算符

运算符是任何编程语言的基础。因此,在不使用运算符的情况下,Go语言的功能是不完整的。运算符允许我们对操作数执行不同类型的运算。在Go语言中,可以根据操作员的不同功能对其进行分类:

  • 算术运算符
  • 关系运算符
  • 逻辑运算符
  • 按位运算符
  • 赋值运算符
  • 杂项运算符

7.1 算术运算符

这些用于对Go语言中的操作数执行算术/数学运算:

  • 加法: +运算符将两个操作数相加。例如,x + y
  • 减法: -运算符减去两个操作数。例如,x-y
  • 乘法: * 运算符将两个操作数相乘。例如,x * y
  • 除法: / 运算符将第一个操作数除以第二个。例如,x / y
  • **求模:**当第一个操作数除以第二个操作数时,运算符返回余数。例如,x%y

注意: -,+,!,&,*,<^也称为一元运算符,一元运算符的优先级更高。++和—运算符来自于语句,它们不是表达式,因此不在运算符层次结构中。

示例

package main

import "fmt"

func main() {
    p := 34
    q := 20

    // 加法
    result1 := p + q
    fmt.Printf("计算结果 p + q = %d", result1)

    // 减法
    result2 := p - q
    fmt.Printf("\n计算结果 p - q = %d", result2)

    // 乘法
    result3 := p * q
    fmt.Printf("\n计算结果 p * q = %d", result3)

    // 除法
    result4 := p / q
    fmt.Printf("\n计算结果 p / q = %d", result4)

    // 求模
    result5 := p % q
    fmt.Printf("\n计算结果 p %% q = %d", result5)
}

输出:

计算结果 p + q = 54
计算结果 p - q = 14
计算结果 p * q = 680
计算结果 p / q = 1
计算结果 p % q = 14

7.2 关系运算符

关系运算符用于比较两个值。

  • ==(等于)运算符检查两个给定的操作数是否相等。如果相等,则返回true。否则,它返回false。例如,5 == 5将返回true。
  • !=(不等于)运算符检查两个给定的操作数是否相等。如果不相等,则返回true。否则,它返回false。它是'=='运算符的精确布尔补码。例如,5!= 5将返回false。
  • >(大于)运算符检查第一个操作数是否大于第二个操作数。如果大于,则返回true。否则,它返回false。例如,6> 5将返回true。
  • <小于)运算符检查第一个操作数是否小于第二个操作数。如果小于,则返回true。否则,它返回false。例如,6 <5将返回false。
  • >=(大于等于)运算符检查第一个操作数是否大于或等于第二个操作数。如果大于等于,则返回true。否则,它返回false。例如,5> = 5将返回true。
  • <=(小于等于)运算符检查第一个操作数是否小于或等于第二个操作数。如果小于等于,则返回true。否则,它返回false。例如,5 <= 5也将返回true。

示例

package main

import "fmt"

func main() {
    p := 34
    q := 20

    // ‘=='(相等)
    result1 := p == q
    fmt.Println(result1)

    // ‘!='(不等于)
    result2 := p != q
    fmt.Println(result2)

    // ‘<‘(小于)
    result3 := p < q
    fmt.Println(result3)

    // ‘>'(大于)
    result4 := p > q
    fmt.Println(result4)

    // ‘>='(大于等于)
    result5 := p >= q
    fmt.Println(result5)

    // ‘<='(小于等于)
    result6 := p <= q
    fmt.Println(result6)

}

输出:

false
true
false
true
true
false

7.3 逻辑运算符

它们用于合并两个或更多的条件/约束,或补充考虑的原始条件的评估。

  • **逻辑AND:**当考虑的两个条件都满足时,&&操作符返回true。否则返回false。例如,当a和b都为真(即非零)时,a && b返回真。
  • 逻辑或: 当其中一个(或两个)条件满足时,||操作符返回true。否则返回false。例如,如果a或b中的一个为真(即非零),a|| b返回true。当然,当a和b都为真时,它返回true。
  • 逻辑非: 即不满足考虑条件,!运算符返回true。否则,它返回false。例如,如果a为假,即a = 0,则!a返回true。

示例

package main

import "fmt"

func main() {
    var p int = 23
    var q int = 60

    if p != q && p <= q {
        fmt.Println("True")
    }

    if p != q || p <= q {
        fmt.Println("True")
    }

    if !(p == q) {
        fmt.Println("True")
    }

}

输出:

True
True
True

7.4 按位运算符

在Go语言中,有6个按位运算符可按位工作或用于逐位操作。以下是按位运算符:

  • (按位与):将两个数字作为操作数,并对两个数字的每一位进行“与”运算。仅当两个位均为1时,AND的结果才为1。
  • | (按位或):将两个数字作为操作数,并对两个数字的每一位进行“或”运算。两个位中的任何一个为1,OR的结果为1。
  • ^(按位XOR):将两个数字作为操作数,并对两个数字的每一位进行XOR(异或)。如果两个位不同,则XOR的结果为1。
  • <<(左移):取两个数字,左移第一个操作数的位,第二个操作数决定移位的位数。
  • >>(右移):取两个数字,右移第一个操作数的位,第二个操作数决定移位的位数。
  • &^(AND NOT):(按位清除)运算符,该运算符的实际操作为&(^)操作。

示例

package main

import "fmt"

func main() {
    p := 134
    q := 320

    // & (AND)
    result1 := p & q
    fmt.Printf("计算结果 p & q = %d", result1)

    // | (OR)
    result2 := p | q
    fmt.Printf("\n计算结果 p | q = %d", result2)

    // ^ (XOR)
    result3 := p ^ q
    fmt.Printf("\n计算结果 p ^ q = %d", result3)

    // << (左移)
    result4 := p << 1
    fmt.Printf("\n计算结果 p << 1 = %d", result4)

    // >> (右移)
    result5 := p >> 1
    fmt.Printf("\n计算结果 p >> 1 = %d", result5)

    // &^ (AND NOT)
    result6 := p &^ q
    fmt.Printf("\n计算结果 p &^ q = %d", result6)

}

输出:

计算结果 p & q = 0
计算结果 p | q = 454
计算结果 p ^ q = 454
计算结果 p << 1 = 268
计算结果 p >> 1 = 67
计算结果 p &^ q = 134

7.5 赋值运算符

赋值运算符用于为变量赋值。赋值运算符的左侧操作数是一个变量,而赋值运算符的右侧操作数是一个值。右侧的值必须与左侧的变量具有相同的数据类型,否则编译器将抛出错误。不同类型的赋值运算符如下所示:

  • =(简单赋值):这是最简单的赋值运算符。该运算符用于将右侧的值分配给左侧的变量。
  • + =(加法赋值):此运算符是+=运算符的组合。该运算符首先将左侧变量的当前值添加到右侧的值,然后将结果分配给左侧的变量。
  • -=(减法赋值):此运算符是-=运算符的组合。该运算符首先从右侧的值中减去左侧变量的当前值,然后将结果分配给左侧的变量。
  • *=(乘法赋值):此运算符是*=运算符的组合。该运算符首先将左侧变量的当前值乘以右侧值,然后将结果分配给左侧变量。
  • /=(除法赋值):此运算符是/=运算符的组合。该运算符首先将左侧变量的当前值除以右侧值,然后将结果分配给左侧变量。
  • %=(模赋值):此运算符是 =运算符的组合。该运算符首先对左侧变量的当前值乘以右侧变量的值,然后将结果赋给左侧变量。
  • &=(按位与赋值):此运算符是=运算符的组合。该运算符首先将左侧变量的当前值与右侧变量进行“按位与”运算,然后将结果分配给左侧变量。
  • ^=(按位异或):此运算符是^=运算符的组合。该运算符首先将左侧变量的当前值与右侧变量进行“按位异或”,然后将结果分配给左侧变量。
  • |=(按位或):此运算符是|=运算符的组合。该运算符首先将左边变量的当前值与右边的值“按位或”,然后将结果分配给左边的变量。

示例

package main 
    
import "fmt"
    
func main() { 
   var p int = 38
    var q int = 70
       
   // “=”(简单赋值) 
   p = q 
   fmt.Println(p) 
       
   // “+=”(加法赋值) 
    //翻译为:p=p+q
    p += q 
   fmt.Println(p) 
       
   //“-=”(减法赋值) 
    //翻译为:p=p-q
   p-=q 
   fmt.Println(p) 
       
   // “*=”(乘法赋值) 
	//翻译为:p=p*q
   p*= q 
   fmt.Println(p) 
       
   // “/=”(除法赋值) 
    // 翻译为:p=p/q
    p /= q 
   fmt.Println(p) 
      
    // “%=”(求模赋值) 
    //翻译为:p=p%q
    p %= q 
   fmt.Println(p) 
      
}

输出:

70
140
70
4900
70
0

7.6 杂项运算符

  • :此运算符返回变量的地址
  • *:此运算符提供指向变量的指针
  • <-:该运算符的名称为接收。它用于从通道接收值。

示例

package main 
    
import "fmt"
    
func main() { 
  a := 94
     
//使用运算符(&)和
//指针间接(*)运算符
  b := &a  
  fmt.Println(*b)  
  *b = 67 
  fmt.Println(a)  
}

输出:

94
67

杂项的指针和地址暂只做了解,后期进阶再详讲

八,流程控制语句

8.1 条件控制

8.1.1 if

//使用if语句
package main
import "fmt"

func main() {

    //取局部变量
    var v int = 700

    //使用if语句
    //检查条件
    if v < 1000 {
        //打印以下内容,条件评估为true
        fmt.Printf("v小于1000\n")
    }

    fmt.Printf("v的值是 : %d\n", v)

}

8.1.2 if…else

// 使用 if...else 语句
package main

import "fmt"

func main() {

    //局部变量
    var v int = 1200

    // 使用if语句检查条件
    if v < 1000 {

        //打印以下内容,如果条件评估为true
        fmt.Printf("v < 1000\n")

    } else {

        //打印以下内容,如果条件评估为false
        fmt.Printf("v > 1000\n")
    }
}

8.1.3 嵌套if

//使用嵌套if语句 
package main 
import "fmt"
  
func main() { 
      
   //两个局部变量
   var v1 int = 400 
   var v2 int = 700 
   
   //使用if语句
   if v1 == 400 { 
         
      // if条件为true时执行 
      if v2 == 700 { 
            
         // if条件为true时,执行打印输出
         fmt.Printf("v1的值是400,v2的值是700\n" ); 
      } 
   } 
    
}

8.1.4 if..else..if

package main 
import "fmt"
  
func main() { 
      
   var v1 int = 700 
   
   if v1 == 100 { 
         
      // 如果条件为真,则显示以下内容 
      fmt.Printf("v1的值是100\n") 
        
   } else if v1 == 200 { 
         
      fmt.Printf("v1的值是200\n") 
        
   } else if v1 == 300 { 
         
      fmt.Printf("v1的值是300\n") 
        
   } else { 
         
      //如果条件都不为真  
      fmt.Printf("没有匹配的值\n") 
   } 
}

if(v == 200)这种可以写成 if v==200,写法随意选

8.2 循环语句

Go语言for循环是一种重复控制语句,它使我们可以编写执行特定次数的循环。

8.2.1 简单的for循环

//使用for循环  
package main 
  
import "fmt"
  
//主函数 
func main() { 
      
    // for 循环
    //这个循环在i = 0时开始执行,直到i<4条件为真
    //post语句是i++
    for i := 0; i < 4; i++{ 
      fmt.Printf("cainiaojc\n")   
    } 
    
}

8.2.2 将for循环作为无限循环

// 使用无限循环  
package main 
  
import "fmt"
   
func main() { 
      
    // 无限循环 
    for { 
      fmt.Printf("cainiaojc\n")   
    } 
    
}

8.2.3 for循环用作while循环

for循环也可以用作while循环。执行此循环,直到给定条件为真为止。当给定条件的值为false时,循环结束。

//for循环与while循环相同 
package main 
  
import "fmt"
   
func main() { 
      
    //while循环
    //for循环执行到
    //i <3条件为真
    i:= 0 
    for i < 3 { 
       i += 2 
    } 
  fmt.Println(i)  
}

8.2.4 for循环中的简单范围

package main 
  
import "fmt"

func main() { 
      
    //这里rvariable是一个数组 
    rvariable := []string{"GFG", "Geeks", "cainiaojc"}  
      
    //index和str存储rvariable的值
    //index存储单个字符串和的索引号
    //str存储给定数组的单个字符串
    for index, str:= range rvariable { 
       fmt.Println(index, str)  
    } 
    
}

输出:

0 GFG
1 Geeks
2 cainiaojc

8.2.5 对字符串使用for循环

package main

import "fmt"

func main() {

    // 字符串作为for循环中的范围
    for i, j := range "XabCd" {
        fmt.Printf("%U 的索引值为 %d\n", j, i)
    }

}

输出:

U+0058 的索引值为 0
U+0061 的索引值为 1
U+0062 的索引值为 2
U+0043 的索引值为 3
U+0064 的索引值为 4

在这里,索引是存储UTF-8编码代码点的第一个字节的变量,而chr是存储给定字符串的字符的变量,而str是字符串。


8.2.6 对于map使用for循环

package main

import "fmt"

func main() {

    mmap := map[int]string{
        22: "Geeks",
        33: "GFG",
        44: "cainiaojc",
    }
    for key, value := range mmap {
        fmt.Println(key, value)
    }
}

输出:

22 Geeks
33 GFG
44 cainiaojc

重要事项:

  • 在for循环的三个语句中不使用括号。
  • 花括号在for循环中是必需的。
  • 左括号应与post语句所在的行相同。
  • 如果数组,字符串,切片或map集合为空,则for循环不会抛出错误并继续其流程。换句话说,如果数组,字符串,切片或map为nil,则for循环的迭代次数为零。

8.3 流程控制关键字

Go语言中的循环控制语句用来改变程序的执行。当给定循环的执行离开其作用域时,在作用域内创建的对象也被销毁。Go语言支持3种循环控制语句:

  1. Break
  2. Goto
  3. Continue

8.3.1 Break

break语句用于终止其所在的循环或语句。 此后,控件将传递到break语句之后出现的语句(如果有)。 如果break语句存在于嵌套循环中,则它仅终止那些包含break语句的循环。

示例

package main

import "fmt"

func main() {
	for i := 0; i < 5; i++ {

		fmt.Println(i)

		//For循环在i = 3时中断
		if i == 3 {
			break
		}
	}

}

输出:

0
1
2
3

8.3.2 goto

该语句用于将控制转移到程序中的标记语句。标签是有效的标识符,放在控件转移处的语句前面。由于难以跟踪程序的控制流,通常不使用goto语句。

image-20250525142537015

示例

package main

import "fmt"

func main() {
	var x int = 0

	//for循环的工作原理与while循环相同
Lable1:
	for x < 8 {
		if x == 5 {
			//使用goto语句
			x = x + 1
			goto Lable1
		}
		fmt.Printf("值为: %d\n", x)
		x++
	}
}

输出:

值为: 0
值为: 1
值为: 2
值为: 3
值为: 4
值为: 6
值为: 7

8.3.3 continue

该语句用于在特定条件下跳过循环的执行部分。 之后,它将控制转移到循环的开始。 基本上,它跳过以下语句,并继续循环的下一个迭代。

package main

import "fmt"

func main() {
    var x int = 0

    //for循环的工作原理与while循环相同
    for x < 8 {
        if x == 5 {

            //跳过两次迭代
            x = x + 2
            continue
        }
        fmt.Printf("值为: %d\n", x)
        x++
    }
}

输出:

值为: 0
值为: 1
值为: 2
值为: 3
值为: 4
值为: 7

8.4 Switch语句

Go 语言中的 switch 语句非常灵活,支持多种用法,相比其他语言(如 Java、C++)有显著差异

8.4.1 值匹配

与大多数语言的 switch 类似,但无需 break(Go 默认不穿透)。

func main() {
    num := 3
    switch num {
    case 1:
        fmt.Println("一")
    case 2:
        fmt.Println("二")
    case 3, 4:  // 匹配多个值(逗号分隔)
        fmt.Println("三或四")
    default:
        fmt.Println("未知")
    }
    // 输出:三或四
}

8.4.2 表达式匹配

case 后可以是任意表达式,而非常量:

func getScore() int {
    return 85
}

func main() {
    switch score := getScore(); { // 分号分隔初始化语句
    case score >= 90:
        fmt.Println("优秀")
    case score >= 80:
        fmt.Println("良好") // 输出:良好
    case score >= 60:
        fmt.Println("及格")
    default:
        fmt.Println("不及格")
    }
}

8.4.3 无条件的 switch

省略 switch 后的变量,直接在每个 case 中写布尔条件:

func checkValue(x int) {
    switch {
    case x < 0:
        fmt.Println("负数")
    case x == 0:
        fmt.Println("零")
    case x > 0:
        fmt.Println("正数") // 若 x=5,输出:正数
    }
}

8.4.4 类型判断

用于判断接口变量的实际类型:

func checkType(v interface{}) {
    switch t := v.(type) {
    case int:
        fmt.Printf("整型: %d\n", t)
    case string:
        fmt.Printf("字符串: %s\n", t)
    default:
        fmt.Printf("未知类型: %T\n", t)
    }
}

func main() {
    checkType(42)           // 输出:整型: 42
    checkType("hello")      // 输出:字符串: hello
    checkType(3.14)         // 输出:未知类型: float64
}

8.4.5 fallthrough 关键字

强制穿透到下一个 case(需显式声明):

func main() {
    x := 10
    switch {
    case x > 5:
        fmt.Println("x > 5")
        fallthrough // 继续执行下一个 case
    case x > 8:
        fmt.Println("x > 8") // 尽管 x=10 满足,但会因 fallthrough 执行
    }
    // 输出:
    // x > 5
    // x > 8
}

8.4.6 作用域与初始化语句

switch 前声明变量,作用域仅限于 switch 块:

func main() {
    switch length := len("Go"); length {
    case 1:
        fmt.Println("长度1")
    case 2:
        fmt.Println("长度2") // 输出:长度2
    default:
        fmt.Println("其他长度")
    }
    // fmt.Println(length) // 错误:length 在此不可见
}

8.4.7 多条件与范围匹配

case 支持逗号分隔多值和范围判断:

func main() {
    month := 5
    switch month {
    case 1, 2, 12:
        fmt.Println("冬季")
    case 3, 4, 5:  // 多个值匹配
        fmt.Println("春季") // 输出:春季
    case 6, 7, 8:
        fmt.Println("夏季")
    case 9, 10, 11:
        fmt.Println("秋季")
    }
}