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

变量

goCopy code
package main

import (
	"fmt"
	"math"
)

func main() {
	// 声明并初始化变量
	var a = "initial"

	// 声明并初始化多个变量
	var b, c int = 1, 2

	// 声明并初始化变量,并推断其类型
	var d = true

	// 声明变量,但没有初始化,Go 会自动赋予零值
	var e float64

	// 使用短声明方式,声明并初始化变量(类型推断)
	f := float32(e)

	// 字符串拼接
	g := a + "foo"
	fmt.Println(a, b, c, d, e, f) // 输出: initial 1 2 true 0 0
	fmt.Println(g)                // 输出: initialfoo

	// 声明常量
	const s string = "constant"
	const h = 500000000
	const i = 3e20 / h

	// 输出常量和数学函数的计算结果
	fmt.Println(s, h, i, math.Sin(h), math.Sin(i))
}

代码解释:

  1. 变量声明和初始化:

    • var a = "initial":声明一个名为 a 的变量,初始值为字符串 "initial"。
    • var b, c int = 1, 2:声明两个整数变量 bc,并分别初始化为 1 和 2。
    • var d = true:声明一个布尔变量 d,初始值为 true
    • var e float64:声明一个浮点数变量 e,因为没有显式初始化,所以会被赋予浮点数类型的零值 0.0。
    • f := float32(e):使用短声明方式,声明并初始化变量 f,类型为 float32,值从变量 e 转换而来。
  2. 字符串拼接:

    • g := a + "foo":使用 + 运算符将字符串 a 和 "foo" 进行拼接,结果存储在变量 g 中。
  3. 输出:

    • fmt.Println(...):使用 fmt.Println 函数输出多个值,以空格分隔。
  4. 常量声明和计算:

    • const s string = "constant":声明一个字符串常量 s,初始值为 "constant"。
    • const h = 500000000:声明一个整数常量 h,初始值为 500000000。
    • const i = 3e20 / h:声明一个浮点数常量 i,计算结果为 3e20(科学计数法表示的值)除以常量 h
  5. 使用数学函数:

    • math.Sin(h)math.Sin(i):使用 math 包中的 Sin 函数分别计算 hi 的正弦值。

for

goCopy code
package main

import "fmt"

func main() {
	// 无限循环,直到遇到 break
	i := 1
	for {
		fmt.Println("loop")
		break
	}

	// 基本的 for 循环,从 7 到 8
	for j := 7; j < 9; j++ {
		fmt.Println(j)
	}

	// 使用 continue 跳过偶数
	for n := 0; n < 5; n++ {
		if n%2 == 0 {
			continue
		}
		fmt.Println(n)
	}

	// 使用 for 循环实现类似 while 的效果
	for i <= 3 {
		fmt.Println(i)
		i = i + 1
	}
}

代码解释:

  1. for {...}:这是一个无限循环,因为没有在循环条件中提供任何条件。在循环体内部,fmt.Println("loop") 输出字符串 "loop",然后通过 break 语句跳出循环。这将导致循环仅迭代一次。
  2. for j := 7; j < 9; j++ {...}:这是一个基本的 for 循环,它从 j 等于 7 开始,每次迭代增加 j 的值,直到 j 小于 9。在循环体内,fmt.Println(j) 打印当前 j 的值。
  3. for n := 0; n < 5; n++ {...}:这个 for 循环在 n 从 0 到 4 变化时迭代。在循环体内部,通过检查 n%2 == 0 来判断 n 是否为偶数,如果是偶数,那么 continue 语句会跳过当前迭代,直接进行下一次迭代。这样,只有奇数会被打印出来。
  4. for i <= 3 {...}:这个 for 循环模拟了类似于 while 的行为。当 i 小于等于 3 时,循环会一直迭代。在每次迭代中,fmt.Println(i) 打印当前的 i 值,然后通过 i = i + 1 增加 i 的值。

if

goCopy code
package main

import "fmt"

func main() {
	// 检查奇偶性
	if 7%2 == 0 {
		fmt.Println("7 is even")
	} else {
		fmt.Println("7 is odd")
	}

	// 检查是否能被 4 整除
	if 8%4 == 0 {
		fmt.Println("8 is divisible by 4")
	}

	// 使用条件语句块进行条件判断和多分支
	if num := 9; num < 0 {
		fmt.Println(num, "is negative")
	} else if num < 10 {
		fmt.Println(num, "has 1 digit")
	} else {
		fmt.Println(num, "has multiple digits")
	}
}

代码解释:

  1. if condition { ... } else { ... }:这是一个基本的 if-else 语句结构。如果 condition 为真(true),则执行位于 { ... } 内的代码块,否则执行位于 else { ... } 内的代码块。

  2. if 7%2 == 0 { ... } else { ... }:这个条件判断语句检查 7 是否为偶数。由于 7 除以 2 的余数不为 0,所以执行 else 块,输出 "7 is odd"。

  3. if 8%4 == 0 { ... }:这个条件判断语句检查 8 是否能被 4 整除。由于 8 能被 4 整除,所以输出 "8 is divisible by 4"。

  4. if num := 9; num < 0 { ... } else if num < 10 { ... } else { ... }:这个条件语句块演示了 Go 语言中的局部变量初始化。在 if 语句的条件中,使用 num := 9 初始化了一个局部变量 num。然后根据 num 的值进行多分支判断:

    • 如果 num 小于 0,输出 "9 is negative"。
    • 否则,如果 num 小于 10,输出 "9 has 1 digit"。
    • 如果上述条件都不满足,则输出 "9 has multiple digits"。

switch

goCopy code
package main

import (
	"fmt"
	"time"
)

func main() {
	// 基本的 switch 语句,匹配不同的 case
	a := 2
	switch a {
	case 1:
		fmt.Println("one")
	case 2:
		fmt.Println("two")
	case 3:
		fmt.Println("three")
	case 4, 5:
		fmt.Println("four or five")
	default:
		fmt.Println("other")
	}

	// 使用无条件表达式的 switch 语句,根据时间判断上午或下午
	t := time.Now()
	switch {
	case t.Hour() < 12:
		fmt.Println("It's before noon")
	default:
		fmt.Println("It's after noon")
	}
}

代码解释:

  1. switch a { ... }:这是一个基本的 switch 语句结构。它根据变量 a 的值,匹配不同的 case 分支。在这个例子中,变量 a 的值为 2,所以输出 "two"。

  2. case 4, 5::这个 case 分支匹配值为 4 或 5 的情况,输出 "four or five"。这里可以同时匹配多个值。

  3. default::当没有任何 case 分支匹配时,将执行 default 分支,输出 "other"。

  4. 使用无条件表达式的 switch 语句:

    • t := time.Now():使用 time.Now() 获取当前时间。
    • switch { ... }:这个 switch 语句没有在 switch 关键字后面添加表达式。每个 case 分支会根据条件判断是否匹配,条件在 case 分支中的表达式中定义。
    • t.Hour() < 12::这个条件判断检查当前时间的小时数是否小于 12。如果为真,执行第一个 case 分支,输出 "It's before noon"。否则,执行 default 分支,输出 "It's after noon"。

array

goCopy code
package main

import "fmt"

func main() {
	// 声明一个长度为 5 的整数数组
	var a [5]int

	// 在数组的第 5 个位置赋值为 100
	a[4] = 100

	// 输出数组的第 2 个位置的值
	fmt.Println("get:", a[2])

	// 输出数组的长度
	fmt.Println("len:", len(a))

	// 声明并初始化一个包含 5 个整数的数组
	b := [5]int{1, 2, 3, 4, 5}
	fmt.Println(b)

	// 声明一个 2x3 的整数数组
	var twoD [2][3]int

	// 使用循环为数组赋值
	for i := 0; i < 2; i++ {
		for j := 0; j < 3; j++ {
			twoD[i][j] = i + j
		}
	}
	fmt.Println("2d: ", twoD)
}

代码解释:

  1. var a [5]int:这是一个长度为 5 的整数数组的声明。在 Go 中,数组的长度也是其类型的一部分。
  2. a[4] = 100:将数组 a 的第 5 个元素(下标为 4)赋值为 100。
  3. fmt.Println("get:", a[2]):输出数组 a 中的第 3 个元素(下标为 2)的值。
  4. fmt.Println("len:", len(a)):输出数组 a 的长度,即 5。
  5. b := [5]int{1, 2, 3, 4, 5}:使用数组字面值初始化一个包含 1 到 5 的整数数组。
  6. var twoD [2][3]int:声明一个二维数组,其维度为 2x3。
  7. 嵌套循环 for i := 0; i < 2; i++for j := 0; j < 3; j++:使用嵌套循环为二维数组 twoD 赋值,数组中的每个元素的值为其行数和列数之和。

slice

goCopy code
package main

import "fmt"

func main() {
	// 使用 make 创建一个长度为 3 的字符串切片
	s := make([]string, 3)

	// 设置切片的元素值
	s[0] = "a"
	s[1] = "b"
	s[2] = "c"

	// 输出切片的第 3 个元素
	fmt.Println("get:", s[2])   // 输出:c
	// 输出切片的长度
	fmt.Println("len:", len(s)) // 输出:3

	// 使用 append 向切片中追加元素
	s = append(s, "d")
	s = append(s, "e", "f")
	fmt.Println(s) // 输出:[a b c d e f]

	// 使用 copy 复制切片
	c := make([]string, len(s))
	copy(c, s)
	fmt.Println(c) // 输出:[a b c d e f]

	// 使用切片操作获取部分切片
	fmt.Println(s[2:5]) // 输出:[c d e]
	fmt.Println(s[:5])  // 输出:[a b c d e]
	fmt.Println(s[2:])  // 输出:[c d e f]

	// 直接初始化切片
	good := []string{"g", "o", "o", "d"}
	fmt.Println(good) // 输出:[g o o d]
}

代码解释:

  1. s := make([]string, 3):使用 make 创建一个长度为 3 的字符串切片。

  2. 切片元素设置:

    • s[0] = "a":设置切片 s 的第一个元素为字符串 "a"。
    • s[1] = "b":设置切片 s 的第二个元素为字符串 "b"。
    • s[2] = "c":设置切片 s 的第三个元素为字符串 "c"。
  3. fmt.Println("get:", s[2]):输出切片 s 的第三个元素,即 "c"。

  4. fmt.Println("len:", len(s)):输出切片 s 的长度,即 3。

  5. 使用 append 向切片追加元素:

    • s = append(s, "d"):追加字符串 "d" 到切片 s
    • s = append(s, "e", "f"):同时追加字符串 "e" 和 "f" 到切片 s
  6. 使用 copy 复制切片:

    • c := make([]string, len(s)):创建一个与切片 s 长度相同的新切片 c
    • copy(c, s):将切片 s 复制到切片 c
  7. 切片操作:

    • s[2:5]:从切片 s 中获取索引从 2 到 4 的元素,即 "c", "d", "e"。
    • s[:5]:从切片 s 中获取索引从 0 到 4 的元素,即 "a", "b", "c", "d", "e"。
    • s[2:]:从切片 s 中获取索引从 2 开始到末尾的元素,即 "c", "d", "e", "f"。
  8. 直接初始化切片:

    • good := []string{"g", "o", "o", "d"}:创建一个包含字符串的切片。

map

goCopy code
package main

import "fmt"

func main() {
	// 使用 make 创建一个字符串到整数的映射
	m := make(map[string]int)

	// 将键值对添加到映射
	m["one"] = 1
	m["two"] = 2

	// 输出映射的内容
	fmt.Println(m)           // 输出:map[one:1 two:2]
	// 输出映射的长度
	fmt.Println(len(m))      // 输出:2
	// 输出指定键的值
	fmt.Println(m["one"])    // 输出:1
	// 输出未定义键的值,默认为 0
	fmt.Println(m["unknown"]) // 输出:0

	// 使用两个返回值检查映射中是否存在指定键
	r, ok := m["unknown"]
	fmt.Println(r, ok) // 输出:0 false

	// 从映射中删除指定键的值
	delete(m, "one")

	// 直接初始化映射
	m2 := map[string]int{"one": 1, "two": 2}
	var m3 = map[string]int{"one": 1, "two": 2}
	fmt.Println(m2, m3)
}

代码解释:

  1. m := make(map[string]int):使用 make 创建一个字符串到整数的映射。

  2. 添加键值对到映射:

    • m["one"] = 1:将键 "one" 对应的值设为 1。
    • m["two"] = 2:将键 "two" 对应的值设为 2。
  3. fmt.Println(m):输出映射的内容,结果为 map[one:1 two:2]

  4. fmt.Println(len(m)):输出映射的长度,结果为 2。

  5. fmt.Println(m["one"]):输出映射中键 "one" 对应的值,结果为 1。

  6. fmt.Println(m["unknown"]):输出映射中未定义键 "unknown" 对应的值,默认为 0。

  7. r, ok := m["unknown"]:使用两个返回值检查映射中是否存在键 "unknown"。r 将会被赋值为该键的值(默认为 0),ok 将会被赋值为 false,表示未找到键 "unknown"。

  8. delete(m, "one"):从映射中删除键 "one" 及其对应的值。

  9. 直接初始化映射:

    • m2 := map[string]int{"one": 1, "two": 2}:创建并初始化一个映射。
    • var m3 = map[string]int{"one": 1, "two": 2}:通过 var 关键字声明并初始化映射。

range

goCopy code
package main

import "fmt"

func main() {
	// 使用 range 迭代切片
	nums := []int{2, 3, 4}
	sum := 0
	for i, num := range nums {
		sum += num
		if num == 2 {
			fmt.Println("index:", i, "num:", num) // 输出:index: 0 num: 2
		}
	}
	fmt.Println(sum) // 输出:9

	// 使用 range 迭代映射
	m := map[string]string{"a": "A", "b": "B"}
	for k, v := range m {
		fmt.Println(k, v) // 输出:b B; a A
	}

	// 使用 range 迭代映射的键
	for k := range m {
		fmt.Println("key", k) // 输出:key a; key b
	}
}

代码解释

  1. nums := []int{2, 3, 4}:声明一个整数切片 nums,包含元素 2、3 和 4。

  2. 使用 range 迭代切片:

    • for i, num := range nums { ... }:使用 range 关键字迭代切片 numsi 是当前元素的索引,num 是当前元素的值。
    • sum += num:将切片中的每个元素值累加到 sum 变量中。
    • if num == 2 { ... }:如果当前元素的值等于 2,输出索引和值。
  3. fmt.Println(sum):输出 sum 的值,即切片中所有元素的和,结果为 9。

  4. 使用 range 迭代映射:

    • for k, v := range m { ... }:使用 range 关键字迭代映射 mk 是当前键,v 是当前键对应的值。
    • fmt.Println(k, v):输出映射中的键和值。
  5. 使用 range 迭代映射的键:

    • for k := range m { ... }:使用 range 关键字迭代映射 m 的键。
    • fmt.Println("key", k):输出映射中的每个键。

func

goCopy code
package main

import "fmt"

// 定义一个接受两个整数参数并返回它们之和的函数
func add(a int, b int) int {
	return a + b
}

// 可简化参数类型定义的函数
func add2(a, b int) int {
	return a + b
}

// 定义一个函数用于检查映射中是否存在指定的键,并返回对应的值和是否存在的布尔值
func exists(m map[string]string, k string) (v string, ok bool) {
	v, ok = m[k]
	return v, ok
}

func main() {
	// 调用 add 函数,计算 1 + 2
	res := add(1, 2)
	fmt.Println(res) // 输出:3

	// 调用 exists 函数,检查映射中是否存在键 "a"
	v, ok := exists(map[string]string{"a": "A"}, "a")
	fmt.Println(v, ok) // 输出:A true
}

代码解释:

goCopy code
package main

import "fmt"

// 定义一个接受两个整数参数并返回它们之和的函数
func add(a int, b int) int {
	return a + b
}

// 可简化参数类型定义的函数
func add2(a, b int) int {
	return a + b
}

// 定义一个函数用于检查映射中是否存在指定的键,并返回对应的值和是否存在的布尔值
func exists(m map[string]string, k string) (v string, ok bool) {
	v, ok = m[k]
	return v, ok
}

func main() {
	// 调用 add 函数,计算 1 + 2
	res := add(1, 2)
	fmt.Println(res) // 输出:3

	// 调用 exists 函数,检查映射中是否存在键 "a"
	v, ok := exists(map[string]string{"a": "A"}, "a")
	fmt.Println(v, ok) // 输出:A true
}
  1. func add(a int, b int) int { ... }:这是一个定义函数 add 的语句。该函数接受两个整数参数 ab,并返回它们的和。
  2. func add2(a, b int) int { ... }:这是一个更简化的函数定义方式。参数类型可以在最后一个参数前进行简化。
  3. func exists(m map[string]string, k string) (v string, ok bool) { ... }:这是定义函数 exists 的语句。该函数接受一个映射 m 和一个键 k,并返回键 k 对应的值 v 和一个布尔值 ok,表示键是否存在。
  4. main 函数中,通过调用 add 函数,将 1 和 2 相加并输出结果。
  5. main 函数中,通过调用 exists 函数,检查映射 map[string]string{"a": "A"} 是否存在键 "a",并输出键对应的值和布尔值。

pointer

goCopy code
package main

import "fmt"

// 传递一个整数值,但在函数内部对参数值进行修改不影响原始值
func add2(n int) {
	n += 2
}

// 传递一个整数的指针,可以通过指针间接修改原始值
func add2ptr(n *int) {
	*n += 2
}

func main() {
	n := 5
	add2(n)
	fmt.Println(n) // 输出:5,因为 add2 函数内部对参数值进行修改,不影响原始值

	add2ptr(&n)
	fmt.Println(n) // 输出:7,因为 add2ptr 函数接受指针参数,通过指针修改了原始值
}

代码解释:

  1. func add2(n int) { ... }:这是一个函数,接受一个整数值作为参数 n。在函数内部,对 n 的修改不会影响传入的原始值,因为传递的是值的副本。
  2. func add2ptr(n *int) { ... }:这是另一个函数,接受一个整数的指针作为参数 n。在函数内部,通过解引用指针 *n 并对其进行修改,可以影响传入的原始值。
  3. main 函数中,声明变量 n 并赋值为 5。
  4. add2(n):调用 add2 函数,并传递 n 的值。这里传递的是值的副本,所以函数内部对参数 n 的修改不会影响原始值。
  5. fmt.Println(n):输出 n 的值,结果为 5,因为 add2 函数内部的修改不影响原始值。
  6. add2ptr(&n):调用 add2ptr 函数,并传递 n 的地址(指针)。这里传递的是指针,所以函数内部对指针解引用并进行修改会影响原始值。
  7. fmt.Println(n):输出 n 的值,结果为 7,因为 add2ptr 函数通过指针修改了原始值。

struct

goCopy code
package main

import "fmt"

// 定义一个名为 user 的结构体类型,包含 name 和 password 字段
type user struct {
	name     string
	password string
}

func main() {
	// 使用不同方式初始化 user 结构体变量
	a := user{name: "wang", password: "1024"}
	b := user{"wang", "1024"}
	c := user{name: "wang"}
	c.password = "1024"
	var d user
	d.name = "wang"
	d.password = "1024"

	// 输出结构体变量的值
	fmt.Println(a, b, c, d) // 输出:{wang 1024} {wang 1024} {wang 1024} {wang 1024}

	// 调用 checkPassword 函数,检查密码是否匹配
	fmt.Println(checkPassword(a, "haha")) // 输出:false

	// 调用 checkPassword2 函数,通过指针传递结构体
	fmt.Println(checkPassword2(&a, "haha")) // 输出:false
}

// 定义函数 checkPassword,接受结构体和密码作为参数,返回密码是否匹配
func checkPassword(u user, password string) bool {
	return u.password == password
}

// 定义函数 checkPassword2,接受结构体指针和密码作为参数,返回密码是否匹配
func checkPassword2(u *user, password string) bool {
	return u.password == password
}

代码解释:

  1. type user struct { ... }:这是定义结构体类型 user 的语句。结构体类型包含两个字段:namepassword

  2. 使用不同的方式初始化 user 结构体变量:

    • a := user{name: "wang", password: "1024"}:通过字段名初始化结构体变量 a
    • b := user{"wang", "1024"}:使用字段值的列表初始化结构体变量 b
    • c := user{name: "wang"}:通过字段名初始化结构体变量 c 的部分字段,然后单独设置其 password 字段。
    • var d user:声明一个变量 d 为零值的结构体,然后分别设置其字段的值。
  3. fmt.Println(a, b, c, d):输出四个结构体变量的值。

  4. checkPassword 函数:接受一个 user 结构体值和一个密码字符串,检查密码是否匹配,并返回布尔值。

  5. checkPassword2 函数:接受一个 user 结构体指针和一个密码字符串,检查密码是否匹配,并返回布尔值。

  6. main 函数中,调用 checkPassword 函数,传递一个结构体值和密码,检查密码是否匹配,结果为 false

  7. main 函数中,调用 checkPassword2 函数,传递一个结构体指针和密码,检查密码是否匹配,结果为 false

struct-method

goCopy code
package main

import "fmt"

type user struct {
	name     string
	password string
}

// 为 user 结构体定义一个方法 checkPassword,接收者为值类型 user
func (u user) checkPassword(password string) bool {
	return u.password == password
}

// 为 user 结构体定义一个方法 resetPassword,接收者为指针类型 *user
func (u *user) resetPassword(password string) {
	u.password = password
}

func main() {
	// 创建一个 user 结构体变量 a
	a := user{name: "wang", password: "1024"}

	// 调用 resetPassword 方法,重置密码
	a.resetPassword("2048")

	// 调用 checkPassword 方法,检查密码是否匹配
	fmt.Println(a.checkPassword("2048")) // 输出:true
}

代码解释:

  1. type user struct { ... }:这是定义结构体类型 user 的语句。
  2. func (u user) checkPassword(password string) bool { ... }:这是为结构体 user 定义一个方法 checkPassword 的语句。方法接收者为结构体值类型 user。该方法接受一个密码字符串作为参数,检查密码是否匹配,并返回布尔值。
  3. func (u *user) resetPassword(password string) { ... }:这是为结构体 user 定义另一个方法 resetPassword 的语句。方法接收者为结构体指针类型 *user。该方法接受一个密码字符串作为参数,重置结构体中的密码字段。
  4. main 函数中,创建一个 user 结构体变量 a,设置初始用户名和密码。
  5. a.resetPassword("2048"):调用 resetPassword 方法,通过指针接收者修改了结构体变量 a 的密码。
  6. fmt.Println(a.checkPassword("2048")):调用 checkPassword 方法,检查密码是否匹配 "2048",输出结果为 true

error

goCopy code
package main

import (
	"errors"
	"fmt"
)

type user struct {
	name     string
	password string
}

// 定义一个函数,查找指定名称的用户
func findUser(users []user, name string) (v *user, err error) {
	for _, u := range users {
		if u.name == name {
			return &u, nil // 返回找到的用户和没有错误
		}
	}
	return nil, errors.New("not found") // 没有找到用户,返回错误
}

func main() {
	// 在给定用户切片中查找 "wang"
	u, err := findUser([]user{{"wang", "1024"}}, "wang")
	if err != nil {
		fmt.Println(err) // 没有错误,输出为空
		return
	}
	fmt.Println(u.name) // 输出:wang

	// 在给定用户切片中查找 "li"
	if u, err := findUser([]user{{"wang", "1024"}}, "li"); err != nil {
		fmt.Println(err) // 输出:not found
		return
	} else {
		fmt.Println(u.name) // 不会执行到这里
	}
}

代码解释:

  1. errors.New("not found"):使用 errors 包中的 New 函数创建一个新的错误实例,内容为 "not found"。
  2. findUser 函数:接受用户切片和名称作为参数,遍历用户切片,如果找到与名称匹配的用户,则返回用户指针和没有错误;如果没有找到,则返回 not found 错误。
  3. main 函数中,调用 findUser 函数,传递用户切片和名称 "wang"。如果找到用户,将用户指针存储在 u 中,如果未找到,将返回一个错误实例,存储在 err 中。
  4. 使用 if err != nil 判断错误是否存在。如果存在错误,则输出错误内容。
  5. 在另一个 if 分支中,再次调用 findUser 函数,查找名称 "li"。如果找到用户,将用户指针存储在 u 中,如果未找到,将返回一个错误实例,存储在 err 中。如果存在错误,输出错误内容为 "not found"。

string

goCopy code
package main

import (
	"fmt"
	"strings"
)

func main() {
	a := "hello"

	// 判断字符串是否包含子串
	fmt.Println(strings.Contains(a, "ll")) // 输出:true

	// 计算子串在字符串中出现的次数
	fmt.Println(strings.Count(a, "l")) // 输出:2

	// 判断字符串是否以指定前缀开头
	fmt.Println(strings.HasPrefix(a, "he")) // 输出:true

	// 判断字符串是否以指定后缀结尾
	fmt.Println(strings.HasSuffix(a, "llo")) // 输出:true

	// 返回子串在字符串中首次出现的索引
	fmt.Println(strings.Index(a, "ll")) // 输出:2

	// 将字符串切片用指定分隔符连接
	fmt.Println(strings.Join([]string{"he", "llo"}, "-")) // 输出:he-llo

	// 重复字符串指定次数
	fmt.Println(strings.Repeat(a, 2)) // 输出:hellohello

	// 替换字符串中的指定子串
	fmt.Println(strings.Replace(a, "e", "E", -1)) // 输出:hEllo

	// 使用指定分隔符分割字符串为切片
	fmt.Println(strings.Split("a-b-c", "-")) // 输出:[a b c]

	// 将字符串转换为小写
	fmt.Println(strings.ToLower(a)) // 输出:hello

	// 将字符串转换为大写
	fmt.Println(strings.ToUpper(a)) // 输出:HELLO

	// 返回字符串的长度(字节数)
	fmt.Println(len(a)) // 输出:5

	b := "你好"
	// 返回字符串的长度(字节数)
	fmt.Println(len(b)) // 输出:6
}

代码解释:

这个代码片段展示了 Go 语言中 strings 包中一些常用的字符串操作函数的用法,包括判断是否包含、计数、前缀和后缀判断、索引查找、连接、重复、替换、分割、大小写转换以及获取字符串长度。注意,在计算字符串长度时,使用的是字节数,而不是字符数。

fmt

goCopy code
package main

import "fmt"

type point struct {
	x, y int
}

func main() {
	s := "hello"
	n := 123
	p := point{1, 2}

	// 使用 fmt.Println 输出多个值
	fmt.Println(s, n) // 输出:hello 123
	fmt.Println(p)    // 输出:{1 2}

	// 使用 fmt.Printf 进行格式化输出
	fmt.Printf("s=%v\n", s)  // 输出:s=hello
	fmt.Printf("n=%v\n", n)  // 输出:n=123
	fmt.Printf("p=%v\n", p)  // 输出:p={1 2}
	fmt.Printf("p=%+v\n", p) // 输出:p={x:1 y:2}
	fmt.Printf("p=%#v\n", p) // 输出:p=main.point{x:1, y:2}

	f := 3.141592653
	fmt.Println(f)          // 输出:3.141592653
	fmt.Printf("%.2f\n", f) // 输出:3.14
}

代码解释:

  1. type point struct { ... }:定义了名为 point 的结构体类型,包含两个整数字段 xy

  2. 使用 fmt.Println(s, n):使用 fmt.Println 函数同时输出多个值,结果为 hello 123

  3. 使用 fmt.Printf 进行格式化输出:

    • fmt.Printf("s=%v\n", s):使用 %v 占位符将变量的值插入字符串中,结果为 s=hello
    • fmt.Printf("n=%v\n", n):同样,使用 %v 插入变量的值,结果为 n=123
    • fmt.Printf("p=%v\n", p):使用 %v 插入结构体变量 p 的值,结果为 p={1 2}
    • fmt.Printf("p=%+v\n", p):使用 %+v 插入结构体变量 p 的值,带有字段名,结果为 p={x:1 y:2}
    • fmt.Printf("p=%#v\n", p):使用 %#v 插入结构体变量 p 的值,带有完整的类型和字段名,结果为 p=main.point{x:1, y:2}
  4. 使用 fmt.Println(f):输出浮点数 f 的值,结果为 3.141592653

  5. 使用 fmt.Printf("%.2f\n", f):使用 %.2f 格式控制符将浮点数 f 格式化为小数点后保留两位的形式,结果为 3.14

json

goCopy code
package main

import (
	"encoding/json"
	"fmt"
)

type userInfo struct {
	Name  string
	Age   int      `json:"age"`    // 自定义 JSON 标签
	Hobby []string `json:"hobbies"` // 自定义 JSON 标签
}

func main() {
	a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "TypeScript"}}

	// 将结构体编码为 JSON 格式的字节切片
	buf, err := json.Marshal(a)
	if err != nil {
		panic(err)
	}
	fmt.Println(buf)         // 输出:[123 34 78 97...]
	fmt.Println(string(buf)) // 输出:{"Name":"wang","age":18,"hobbies":["Golang","TypeScript"]}

	// 使用 json.MarshalIndent 进行格式化输出
	buf, err = json.MarshalIndent(a, "", "\t")
	if err != nil {
		panic(err)
	}
	fmt.Println(string(buf))

	// 将 JSON 格式的字节切片解码为结构体
	var b userInfo
	err = json.Unmarshal(buf, &b)
	if err != nil {
		panic(err)
	}
	fmt.Printf("%#v\n", b) // 输出:main.userInfo{Name:"wang", Age:18, Hobby:[]string{"Golang", "TypeScript"}}
}

代码解释:

  1. type userInfo struct { ... }:定义了 userInfo 结构体类型,包含 NameAgeHobby 字段。使用 json 标签来自定义字段在 JSON 中的名称。
  2. json.Marshal(a):使用 json.Marshal 函数将 a 结构体编码为 JSON 格式的字节切片。
  3. json.MarshalIndent(a, "", "\t"):使用 json.MarshalIndent 函数对 a 结构体进行格式化编码,第二个参数是前缀,第三个参数是缩进字符串。
  4. json.Unmarshal(buf, &b):使用 json.Unmarshal 函数将 JSON 格式的字节切片解码为结构体变量 b

time

goCopy code
package main

import (
	"fmt"
	"time"
)

func main() {
	// 获取当前时间
	now := time.Now()
	fmt.Println(now) // 输出当前时间,类似:2022-03-27 18:04:59.433297 +0800 CST m=+0.000087933

	// 构造指定时间
	t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC)
	t2 := time.Date(2022, 3, 27, 2, 30, 36, 0, time.UTC)
	fmt.Println(t) // 输出:2022-03-27 01:25:36 +0000 UTC

	// 获取时间的年、月、日、小时、分钟
	fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute()) // 输出:2022 March 27 1 25

	// 格式化时间为字符串
	fmt.Println(t.Format("2006-01-02 15:04:05")) // 输出:2022-03-27 01:25:36

	// 计算时间差
	diff := t2.Sub(t)
	fmt.Println(diff)                           // 输出:1h5m0s
	fmt.Println(diff.Minutes(), diff.Seconds()) // 输出:65 3900

	// 解析字符串为时间对象
	t3, err := time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:36")
	if err != nil {
		panic(err)
	}
	fmt.Println(t3 == t) // 输出:true

	// 获取当前时间的 Unix 时间戳
	fmt.Println(now.Unix()) // 输出当前时间的 Unix 时间戳,类似:1648738080
}

代码解释:

  1. time.Now():获取当前时间。
  2. time.Date(year, month, day, hour, minute, second, nanosecond, location):构造指定时间。
  3. t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute():获取时间的年、月、日、小时、分钟。
  4. t.Format(layout):将时间格式化为指定的字符串。
  5. t2.Sub(t):计算时间差。
  6. time.Parse(layout, value):将字符串解析为时间对象。
  7. now.Unix():获取当前时间的 Unix 时间戳。

strconv

goCopy code
package main

import (
	"fmt"
	"strconv"
)

func main() {
	// 将字符串转换为浮点数
	f, _ := strconv.ParseFloat("1.234", 64)
	fmt.Println(f) // 输出:1.234

	// 将字符串转换为整数
	n, _ := strconv.ParseInt("111", 10, 64)
	fmt.Println(n) // 输出:111

	// 支持十六进制转换
	n, _ = strconv.ParseInt("0x1000", 0, 64)
	fmt.Println(n) // 输出:4096

	// 将字符串转换为整数,简便函数 Atoi
	n2, _ := strconv.Atoi("123")
	fmt.Println(n2) // 输出:123

	// Atoi 在无法解析时会返回 0 和错误信息
	n2, err := strconv.Atoi("AAA")
	fmt.Println(n2, err) // 输出:0 strconv.Atoi: parsing "AAA": invalid syntax
}

代码解释:

  1. strconv.ParseFloat(input, bitSize):将字符串转换为浮点数,bitSize 表示浮点数的位数。
  2. strconv.ParseInt(input, base, bitSize):将字符串转换为整数,base 表示输入的字符串是何种进制(0 表示自动识别进制),bitSize 表示整数的位数。
  3. strconv.Atoi(input):将字符串转换为整数,这是 strconv.ParseInt 的简便函数,自动识别进制。
  4. strconv.Atoi 中,无法解析时会返回 0 和错误信息。

env

goCopy code
package main

import (
	"fmt"
	"os"
	"os/exec"
)

func main() {
	// 输出命令行参数
	fmt.Println(os.Args) // 输出:[/var/folders/8p/n34xxfnx38dg8bv_x8l62t_m0000gn/T/go-build3406981276/b001/exe/main a b c d]

	// 获取环境变量
	fmt.Println(os.Getenv("PATH")) // 输出环境变量 PATH 的值

	// 设置环境变量
	fmt.Println(os.Setenv("AA", "BB")) // 设置环境变量 AA 的值为 BB

	// 执行外部命令并获取输出
	buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput()
	if err != nil {
		panic(err)
	}
	fmt.Println(string(buf)) // 输出 grep 命令在 /etc/hosts 中查找的结果
}

代码解释:

  1. os.Args:获取命令行参数,包括程序名和参数列表。
  2. os.Getenv(name):获取环境变量的值。
  3. os.Setenv(name, value):设置环境变量的值。
  4. exec.Command(command, args...):创建一个命令对象,command 表示命令名称,args... 表示命令参数。
  5. cmd.CombinedOutput():执行命令并获取标准输出和标准错误输出,如果命令执行失败,则返回错误。
相关推荐
向阳12181 小时前
什么是 Go 语言?
开发语言·后端·golang
Shinobi_Jack1 小时前
Go 加密算法工具方法
开发语言·golang·哈希算法
好奇的菜鸟1 小时前
Go语言的零值可用性:优势与限制
开发语言·后端·golang
风霜不见闲沉月2 小时前
golang使用etcd版本问题
开发语言·golang·etcd
灼华十一8 小时前
数据结构-布隆过滤器和可逆布隆过滤器
数据结构·算法·golang
Ai 编码助手14 小时前
Go语言 实现将中文转化为拼音
开发语言·后端·golang
hummhumm14 小时前
第 12 章 - Go语言 方法
java·开发语言·javascript·后端·python·sql·golang
hummhumm14 小时前
第 8 章 - Go语言 数组与切片
java·开发语言·javascript·python·sql·golang·database
杜杜的man14 小时前
【go从零单排】Directories、Temporary Files and Directories目录和临时目录、临时文件
开发语言·后端·golang
qq_3089574714 小时前
Gin 框架入门(GO)-1
开发语言·golang·gin