Go 语言入门指南:基础语法和常用特性解析 02

94 阅读10分钟

Go语言的基础语法

使用包的原因:

  1. 模块化和代码组织:包提供了一种模块化的方式来组织代码。将相关的函数、类型和变量放在同一个包中,可以提高代码的可读性、可维护性和重用性。包结构可以帮助开发者更好地组织和管理项目中的代码。
  2. 封装和信息隐藏:包可以通过封装隐藏内部实现细节,只暴露必要的接口给外部使用。这样可以保护代码的私密性,防止其他代码直接访问和修改包的内部状态,提供了一种信息隐藏的机制。
  3. 名称空间和标识符冲突解决:使用包可以创建独立的命名空间,防止不同包中的标识符冲突。包名加上访问符号 . 或者包别名的方式,可以访问其他包中的代码,避免了全局命名冲突的问题。
  4. 代码复用和共享:包可以作为一个可重用的模块被其他程序引用和使用。通过导入其他的包,我们可以使用其中的函数、变量和类型,避免了重复编写相同的代码,提高了编码效率。
  5. 分布式开发和团队协作:包的使用方便了分布式开发和团队协作。不同的开发者可以独立地编写和管理各自的包,并通过版本管理工具将其集成到一个项目中。这样就可以高效地开发大型项目或团队协作,每个人负责一个或多个包的开发。
  6. 代码可维护性:将代码以包的形式组织起来,可以提高代码的可维护性。包可以分解复杂的问题为更小的子问题,让代码更易于理解、测试和修改。代码的职责划分清晰,修改一个包不会对其他包产生意外的影响。

包的声明

package main//1.进行包的声明,建议:声明这个包的和所在的文件夹同名
            //2.main包是程序的入口包,一般main函数会放在这个包下

// 3.然后在代码中通过 import 关键字引入包,就可以使用其中的功能了:
import (
    "fmt"
    "mycode/text" //包名从$GOPATH/src/后开始计算的,使用/进行路径分隔
)

func Myfunc(){ //大写字母开头的函数可以被其它包引用
}

func main(){
     //引用其它包的函数 包名+.+函数名
     fmt.Println("Hello world")
     text.Text()
}

闭包

  1. 什么是闭包
    闭包就是和其相关的引用环境组成的整体。
  2. 案例展示
package main  
  
import "fmt"  
  
// 函数求值  
func getSum() func(int) int {  
    var sum int = 0  
    return func(num int) int {  
        sum = sum + num  
        return sum  
    }  
}  
  
// 闭包: 返回的匿名函数 + 匿名函数以外的变量num  
// 匿名函数中的变量会一直保存在内存中, 可以一直使用  
func main() {  
    f := getSum()  
    fmt.Println(f(1)) // sum = 0 + 1 = 2  
    fmt.Println(f(2)) // sum = 1 + 2 = 3  
    fmt.Println(f(3)) // sum = 3 + 3 = 6  
}
  1. 闭包的本质
    闭包的本质依旧是一个匿名函数,只是这个函数引入外界的变量/参数
    匿名函数+引用的变量/参数 = 闭包
  2. 特点
    (1) 返回的是一个匿名函数,但是这个匿名函数引用的函数外的变量/参数,因此这个匿名函数就和变量/参数形成一个主题,构成闭包。
    (2) 闭包中使用的变量/参数会一直保存在内存中,所以会一直使用——>意味着闭包不能滥用

常用字符串操作

  1. 字符串长度 len(str)
  2. 字符串遍历
//方式一
for i, value := range str{
    fmt.Printf("%d",i)
    fmt.Printf("%c",value)
    fmt.Printf("索引%d 字母为%c",i,value)
    //对str进行遍历 ,遍历索引被i接收,结果数值被value接收
}
//方式二 利用r := []rune(str) 将字符串转为切片
r := []rune(str)
for i := 0 ; i < len(r) ; i ++{
    fmt.Printf("%c",r[i])
}

  1. 字符串转数字n,err := strconv.Atoi("66") // a to i
  2. 数字转字符串str := strconv.ltoa(12345) // i to a
  3. 查找子串是否在字符串中 strings.Contains("abcde","abc")
  4. 统计一个字符串有几个指定的子串 count := strings.Count("abcabcabc","abc")
  5. 返回一个子串在字符串第一次出现的索引,没有返回-1
    index := strings.Index("abcdef","cd")
  6. 字符串替换
    str := stringsReplace("gogogo", "golang", n ) // n是替换n个 n=-1 替换所有
  7. 去掉字符串左右指定字符
strings.Trim("~abc~","~") //去掉左右
strings.TrimSpace("   abc    ","~") // 去掉空格
strings.TrimRight("~abc~","~") //去掉右边
strings.TrimLeft("~abc~","~") //去掉左边

数组

定义 var arr [n]数据类型
遍历 for i := 0 ; i < len(arr) ; i++

切片

在Go语言中,Slice(切片)是一种动态数组的抽象类型。它提供了对数组的某个连续片段的引用,可以按需动态增长和缩减。

Slice 的声明和使用方式如下:

var slice []T      // 声明一个切片变量,T代表切片中元素的类型
slice := []T{1, 2, 3}  // 声明一个切片并初始化

**

其中,T 表示切片中元素的类型,可以是任意的数据类型。

创建切片有两种方式:

  1. 从现有的数组或切片中创建切片:可以通过 array[start:end] 或 slice[start:end] 的方式创建一个切片,切片包含了从索引 start 到 end-1 的元素。例如:

    array := [5]int{1, 2, 3, 4, 5}
    slice := array[1:3] // 创建从索引1到2的切片,结果为[2, 3]
    

    **

  2. 使用内置的 make 函数创建切片:可以使用 make 函数创建指定长度和容量的切片。长度是切片中已经使用的元素个数,容量是底层数组中可供切片使用的元素个数。例如:

    slice := make([]int, 3, 5) // 创建一个长度为3,容量为5的切片
    

    **

    make([]T, length, capacity) 创建了一个初始长度为 length,容量为 capacity 的切片。

切片有以下几个重要的属性和方法:

  • len(slice):获取切片的长度。
  • cap(slice):获取切片的容量。
  • slice[index]:访问切片中指定索引的元素。
  • slice[start:end]:获取从索引 start 到 end-1 的子切片。
  • append(slice, element):在切片末尾追加元素,并返回新的切片。
  • copy(destSlice, srcSlice):将源切片中的元素拷贝到目标切片中。

切片是引用类型,它们在底层引用了一个数组,并且可以自动扩容。当切片容量不足以存储新的元素时,底层数组会自动扩展以适应新的元素。切片的长度和容量可以通过内置函数 len() 和 cap() 来获取。

切片提供了一种方便且灵活的方式来处理变长的数据集合,广泛应用于Go语言中。它们经常用于动态存储和操作数据,特别是在需要经常改变大小的情况下。

map

在Go语言中,Map(映射)是一种无序的键值对集合,也被称为字典或关联数组。Map中的键(key)和值(value)可以是任意类型,键必须是唯一的。

你可以通过以下方式声明和初始化一个Map变量:

var m map[keyType]valueType                // 声明一个Map变量
m := make(map[keyType]valueType)           // 使用make函数创建一个Map
m := map[keyType]valueType{key: value, ...} // 声明并初始化一个Map

**

其中,keyType 和 valueType 分别表示键和值的类型,可以是任意类型。使用 make 函数创建Map时,需要指定键值类型。

Map的常见操作包括:

  • 插入键值对:可以使用 mapName[key] = value 的方式插入键值对。如:

    m := make(map[string]int)
    m["apple"] = 1
    m["orange"] = 2
    

    **

  • 获取值:可以通过 mapName[key] 的方式获取对应的值。如:

    fmt.Println(m["apple"]) // 输出:1
    

    **

  • 删除键值对:可以使用内置的 delete 函数删除指定的键值对。如:

    delete(m, "apple")
    

    **

  • 判断键是否存在:可以通过以下方式判断键是否存在:

    value, ok := m[key]
    if ok {
        // 键存在,执行相关操作
    } else {
        // 键不存在
    }
    

    **

  • 遍历Map:可以使用 range 关键字遍历Map中的所有键值对。如:

    for key, value := range m {
        // 处理每个键值对
    }
    

    **

Map是一种引用类型,存储的是对底层数据结构的引用。Map的大小不固定,可以根据需要动态增长。它是一种高效的数据结构,可以用于快速查找和索引。

struct

在Go语言中,struct(结构体)是一种用户定义的复合类型,用于表示一组相关的字段(属性)的集合。结构体可以包含不同类型的字段,并且可以根据需要自定义。

你可以通过以下方式声明和使用一个结构体:

type Person struct {
    Name string
    Age  int
    City string
}

// 创建结构体实例并初始化
person := Person{Name: "Alice", Age: 25, City: "New York"}

// 访问结构体字段
fmt.Println(person.Name) // 输出:Alice
fmt.Println(person.Age)  // 输出:25
fmt.Println(person.City) // 输出:New York

**

在结构体中,字段的类型在冒号后面声明,字段名在冒号前面声明。可以使用点运算符 . 来访问结构体中的字段。

结构体的字段可以包括任何合法的Go类型,包括内置类型、自定义类型、数组、切片、Map等。而且结构体类型可以嵌套其他结构体类型,形成更复杂的数据结构。

结构体的常见操作包括:

  • 实例化和初始化:声明结构体类型后,可以通过结构体字面量或赋值语句对结构体进行初始化。
  • 访问字段:通过使用点运算符 . 可以访问结构体实例中的字段,可以读取和修改字段的值。
  • 嵌入结构体:可以在一个结构体中嵌入另一个结构体,以形成更复杂的数据结构。
  • 比较结构体:可以使用 == 运算符对结构体进行逐个字段的比较。
  • 指针与结构体:可以使用指针来操作结构体,通过指针可以直接修改结构体的字段值。
  • 方法与结构体:可以为结构体定义方法,结构体方法是一种关联到结构体类型的函数。

结构体是Go语言中常用的一种数据结构,它被广泛用于表示自定义类型、数据模型、数据库映射等。通过结构体,可以组织和管理更复杂的数据,并在代码中进行高效地访问和处理。

结构体方法 Go语言中的方法被定义在结构体类型上,语法格式如下:

func (接收者 Receiver类型) 方法名(参数列表) 返回值列表 {
    // 方法体
}

** 其中,接收者可以是类型名加上*或者,表示指针接收者或值接收者。

  • 值接收者:方法接收的是类型的一份副本,修改副本不会影响原始值。
  • 指针接收者:方法接收的是类型的指针,可以修改指针指向的原始值。

例子:

type Rectangle struct {
    width, height float64
}

// 值接收者的方法
func (r Rectangle) Area() float64 {
    return r.width * r.height
}

// 指针接收者的方法
func (r *Rectangle) Scale(scaleFactor float64) {
    r.width *= scaleFactor
    r.height *= scaleFactor
}

** 调用方法的语法为 实例.方法名(),或者通过指针调用方法的语法为 指针.方法名()

例子:

r := Rectangle{width: 5, height: 10}
fmt.Println(r.Area()) // 输出:50

p := &r
p.Scale(2)
fmt.Println(r.width)  // 输出:10
fmt.Println(r.height) // 输出:20