Go 语言入门指南:基础语法和常用特性解析(上)| 青训营

90 阅读8分钟

1.引言

Go 语言是一种开源的编程语言,由 Google 的 Robert Griesemer, Rob Pike 和 Ken Thompson 在 2007 年设计,并于 2009 年正式发布[。Go 语言的设计目标是实现高效、可靠、简洁、易读和跨平台的软件开发]。Go 语言的特点包括:

1. 静态类型:Go 语言是一种静态类型的语言,也就是说,在编译时就确定了变量的类型,而不是在运行时。这样可以提高程序的运行效率和安全性,避免一些类型错误的发生。

2. 自动垃圾回收:Go 语言支持自动垃圾回收(GC),也就是说,程序员不需要手动管理内存的分配和释放,而是由运行时系统自动完成。这样可以减少内存泄漏和空指针等问题,简化编程的难度。

3..并发编程: Go 语言提供了一套原生的并发编程机制,包括 goroutine 和 channel。goroutine 是一种轻量级的线程,可以在一个进程中创建成千上万个,并且可以自动调度和切换。channel 是一种用于在不同 goroutine 之间传递数据的管道,可以实现同步或异步的通信。Go 语言的并发编程模型遵循了 CSP(Communicating Sequential Processes)理论],强调以通信来共享内存,而不是以共享内存来通信。

4..函数式编程:Go 语言支持函数式编程的一些特性,例如 函数作为一等公民,可以作为参数或返回值传递;闭包,可以捕获外部变量的值;匿名函数,可以在需要时定义和使用;多返回值,可以同时返回多个值或错误;延迟执行,可以在函数返回前执行一些清理或释放资源的操作。

5..面向接口编程:Go 语言没有传统意义上的类和继承的概念,而是采用了 结构体 和 接口 的方式来实现面向对象编程。结构体是一种自定义的数据类型,可以包含多个字段(属性)和方法(行为)。接口是一种抽象的类型,只定义了一组方法签名,而不指定具体的实现。任何类型只要实现了接口中的所有方法,就可以被认为是该接口类型。这样可以实现多态和解耦的效果,也避免了继承带来的复杂性和脆弱性。

2.基础语法

1.变量和常量

变量是程序中用来存储数据的标识符,常量是程序中不可改变的数据。在 Go 语言中,变量和常量都需要先声明后使用。

变量声明有以下几种方式:

1.使用 var 关键字声明一个或多个变量,并可选地指定类型和初始值。例如:

a int // 声明一个整型变量 a

var b, c string // 声明两个字符串变量 b 和 c

var d = true // 声明一个布尔变量 d,并赋值为 true

var e, f = 1.2, "hello" // 声明两个变量 e 和 f,并分别赋值为 1.2 和 "hello"

2.使用短变量声明 := 在函数内部声明并初始化一个或多个变量,无需指定类型,由编译器自动推断。例如:

  g := 10 // 声明一个整型变量 g,并赋值为 10
	h, i := "world", false // 声明两个变量 h 和 i,并分别赋值为 "world" 和 false

3.使用圆括号 () 声明一组变量,可以提高代码的可读性。例如:

var (
    j int = 100
    k string = "Go"
    l bool = true
)

常量声明有以下几种方式:

1.使用 const 关键字声明一个或多个常量,并必须指定初始值。例如:

const m = 3.14 // 声明一个常量 m,并赋值为 3.14
const n, o = "hello", "world" // 声明两个常量 n 和 o,并分别赋值为 "hello" 和 "world"

2.使用圆括号 () 声明一组常量,可以提高代码的可读性。例如:

const (
    p = 1
    q = 2
    r = 3
)

3.使用 iota 常量生成器,可以自动为一组常量赋值,从 0 开始,每次递增 1。例如:

const (
    s = iota // s = 0
    t        // t = 1
    u        // u = 2
)

数据类型

Go 语言支持以下几种基本的数据类型:

  • 布尔类型:表示真或假的值,只有两个预定义的常量:true 和 false。例如:
var a bool = true // 声明一个布尔变量 a,并赋值为 true
var b bool = false // 声明一个布尔变量 b,并赋值为 false
  • 数值类型:表示整数、浮点数和复数等数值。

  • 浮点型:表示小数点后有固定位数的实数,有以下两种长度:

    • float32:表示 IEEE-754 单精度浮点数,占用 32 位。
    • float64:表示 IEEE-754 双精度浮点数,占用 64 位。
  • 复数型:表示实部和虚部都是浮点数的复数,有以下两种长度:

complex64:表示实部和虚部都是 float32 的复数,占用 64 位。 complex128:表示实部和虚部都是 float64 的复数,占用 128 位。

  • 字符串类型:表示一系列的字节或字符,使用双引号 " 或反引号 ` 包裹。例如:
var a string = "Hello, world!" // 声明一个字符串变量 a,并赋值为 "Hello, world!"
var b string = `This is a
multi-line
string` // 声明一个多行字符串变量 b,并赋值为 `This is a
        // multi-line
        // string`
  • 数组类型:表示固定长度的同类型元素的集合,使用方括号 [] 指定长度和元素类型。例如:
var a [3]int // 声明一个长度为 3 的整型数组 a
var b [2][2]string // 声明一个 2x2 的字符串二维数组 b
var c = [5]bool{true, false, true, false, true} // 声明并初始化一个长度为 5 的布尔数组 c
var d = [...]int{1, 2, 3, 4, 5} // 声明并初始化一个长度由编译器推断的整型数组 d
  • 切片类型:表示可变长度的同类型元素的集合,使用方括号 [] 指定元素类型,但不指定长度。切片是对底层数组的引用,可以使用内置函数 make 创建切片,并指定长度和容量。例如:
var a []int // 声明一个整型切片 a
var b = []string{"a", "b", "c"} // 声明并初始化一个字符串切片 b
var c = make([]bool, 3) // 使用 make 函数创建一个长度为 3 的布尔切片 c
var d = make([]float64, 2, 4) // 使用 make 函数创建一个长度为 2,容量为 4 的浮点切片 d
  • 结构体类型:表示自定义的数据类型,可以包含多个字段(属性)和方法(行为),使用关键字 struct 定义结构体类型,并使用花括号 {} 初始化结构体实例。例如:
type Person struct { // 定义一个名为 Person 的结构体类型
    name string // 定义一个名为 name 的字符串字段
    age int // 定义一个名为 age 的整型字段
}

func (p Person) SayHello() { // 定义一个名为 SayHello 的方法,接收一个 Person 类型的参数 p
    fmt.Printf("Hello, I am %s, %d years old.\n", p.name, p.age) // 打印 p 的 name 和 age
}

var a Person // 声明一个 Person 类型的变量 a
var b = Person{"Alice", 20} // 声明并初始化一个 Person 类型的变量 b,并赋值为 {"Alice", 20}
var c = Person{name: "Bob", age: 30} // 声明并初始化一个 Person 类型的变量 c,并使用字段名赋值为 {name: "Bob", age: 30}
  • 接口类型:表示抽象的类型,只定义了一组方法签名,而不指定具体的实现,使用关键字 interface 定义接口类型。任何类型只要实现了接口中的所有方法,就可以被认为是该接口类型。例如:
type Animal interface { // 定义一个名为 Animal 的接口类型
    Speak() string // 定义一个名为 Speak 的方法,返回一个字符串
}

type Dog struct {} // 定义一个名为 Dog 的结构体类型

func (d Dog) Speak() string { // 为 Dog 类型实现 Speak 方法,返回 "Woof!"
    return "Woof!"
}

type Cat struct {} // 定义一个名为 Cat 的结构体类型

func (c Cat) Speak() string { // 为 Cat 类型实现 Speak 方法,返回 "Meow!"
    return "Meow!"
}

var a Animal // 声明一个 Animal 类型的变量 a
var b = Dog{} // 声明并初始化一个 Dog 类型的变量 b
var c = Cat{} // 声明并初始化一个 Cat 类型的变量 c
a = b // 将 b 赋值给 a,因为 Dog 类型实现了 Animal 接口
fmt.Println(a.Speak()) // 打印 "Woof!"
a = c // 将 c 赋值给 a,因为 Cat 类型实现了 Animal 接口
fmt.Println(a.Speak()) // 打印 "Meow!"

流程控制

流程控制是程序中用来控制执行顺序和逻辑的语句,Go 语言支持以下几种流程控制语句:

  • 条件语句:根据条件判断执行不同的分支,使用关键字 if 和 else 实现。例如:
a := 10 // 声明并初始化一个整型变量 a,并赋值为 10
if a > 0 { // 如果 a 大于 0
    fmt.Println("a is positive") // 打印 "a is positive"
} else if a < 0 { // 否则如果 a 小于 0
    fmt.Println("a is negative") // 打印 "a is negative"
} else { // 否则
    fmt.Println("a is zero") // 打印 "a is zero"
}
  • 循环语句:重复执行一段代码,直到满足结束条件,使用关键字 for 实现。Go 语言没有 while 和 do-while 循环语句,只有 for 循环语句。例如:
for i := 1; i <= 10; i++ { // 使用 for 初始化、条件和递增三个部分实现类似 C 语言的循环
    fmt.Println(i) // 打印 i 的值
}

sum := 0 // 声明并初始化一个整型变量 sum,并赋值为 0
for sum < 100 { // 使用 for 只有条件部分实现类似 while 的循环
    sum += 10 // 将 sum 加上 10
}
fmt.Println(sum) // 打印 sum 的值

for { // 使用 for 没有任何部分实现无限循环
    fmt.Println("Hello, world!") // 打印 "Hello, world!"
    break // 使用 break 关键字跳出循环
}
  • 选择语句:根据表达式的值选择执行不同的分支,使用关键字 switch 和 case 实现。Go 语言的 switch 语句不需要使用 break 关键字来结束每个分支,而是默认只执行一个分支,除非使用 fallthrough 关键字来继续执行下一个分支。例如:
a := "Go" // 声明并初始化一个字符串变量 a,并赋值为 "Go"
switch a { // 使用 switch 语句根据 a 的值选择执行不同的分支
case "Java": // 如果 a 等于 "Java"
    fmt.Println("a is Java") // 打印 "a is Java"
case "Python": // 如果 a 等于 "Python"
    fmt.Println("a is Python") // 打印 "a is Python"
case "Go": // 如果 a 等于 "Go"
    fmt.Println("a is Go") // 打印 "a is Go"
    fallthrough // 使用 fallthrough 关键字继续执行下一个分支
default: // 默认分支
    fmt.Println("a is something else") // 打印 "a is something else"
}
  • 跳转语句:改变程序的执行流程,使用关键字 breakcontinue 和 goto 实现。例如:
for i := 1; i <= 10; i++ { // 使用 for 循环从 1 到 10
    if i == 5 { // 如果 i 等于 5
        break // 使用 break 关键字跳出循环
    }
    fmt.Println(i) // 打印 i 的值
}

for i := 1; i <= 10; i++ { // 使用 for 循环从 1 到 10
    if i % 2 == 0 { // 如果 i 是偶数
        continue // 使用 continue 关键字跳过本次循环
    }
    fmt.Println(i) // 打印 i 的值
}

i := 1 // 声明并初始化一个整型变量 i,并赋值为 1
LOOP: // 定义一个名为 LOOP 的标签
for { // 使用 for 实现无限循环
    if i > 10 { // 如果 i 大于 10
        break // 跳出循环
    }
    fmt.Println(i) // 打印 i 的值
    i++ // 将 i 加一
    goto LOOP // 使用 goto 关键字跳转到 LOOP 标签处继续执行
}