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

变量

goCopy code
package mainimport ("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 0fmt.Println(g)                // 输出: initialfoo// 声明常量const s string = "constant"const h = 500000000const 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 mainimport "fmt"func main() {// 无限循环,直到遇到 breaki := 1for {fmt.Println("loop")break}// 基本的 for 循环,从 7 到 8for 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 mainimport "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 mainimport ("fmt""time"
)func main() {// 基本的 switch 语句,匹配不同的 casea := 2switch 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 mainimport "fmt"func main() {// 声明一个长度为 5 的整数数组var a [5]int// 在数组的第 5 个位置赋值为 100a[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 mainimport "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 mainimport "fmt"func main() {// 使用 make 创建一个字符串到整数的映射m := make(map[string]int)// 将键值对添加到映射m["one"] = 1m["two"] = 2// 输出映射的内容fmt.Println(m)           // 输出:map[one:1 two:2]// 输出映射的长度fmt.Println(len(m))      // 输出:2// 输出指定键的值fmt.Println(m["one"])    // 输出:1// 输出未定义键的值,默认为 0fmt.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 mainimport "fmt"func main() {// 使用 range 迭代切片nums := []int{2, 3, 4}sum := 0for i, num := range nums {sum += numif 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 mainimport "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 + 2res := 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 mainimport "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 + 2res := 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 mainimport "fmt"// 传递一个整数值,但在函数内部对参数值进行修改不影响原始值
func add2(n int) {n += 2
}// 传递一个整数的指针,可以通过指针间接修改原始值
func add2ptr(n *int) {*n += 2
}func main() {n := 5add2(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 mainimport "fmt"// 定义一个名为 user 的结构体类型,包含 name 和 password 字段
type user struct {name     stringpassword string
}func main() {// 使用不同方式初始化 user 结构体变量a := user{name: "wang", password: "1024"}b := user{"wang", "1024"}c := user{name: "wang"}c.password = "1024"var d userd.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 mainimport "fmt"type user struct {name     stringpassword 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 结构体变量 aa := 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 mainimport ("errors""fmt"
)type user struct {name     stringpassword 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 foundreturn} 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 mainimport ("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)) // 输出:5b := "你好"// 返回字符串的长度(字节数)fmt.Println(len(b)) // 输出:6
}

代码解释:

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

fmt

goCopy code
package mainimport "fmt"type point struct {x, y int
}func main() {s := "hello"n := 123p := point{1, 2}// 使用 fmt.Println 输出多个值fmt.Println(s, n) // 输出:hello 123fmt.Println(p)    // 输出:{1 2}// 使用 fmt.Printf 进行格式化输出fmt.Printf("s=%v\n", s)  // 输出:s=hellofmt.Printf("n=%v\n", n)  // 输出:n=123fmt.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.141592653fmt.Println(f)          // 输出:3.141592653fmt.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 mainimport ("encoding/json""fmt"
)type userInfo struct {Name  stringAge   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 userInfoerr = 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 mainimport ("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)                           // 输出:1h5m0sfmt.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 mainimport ("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// 将字符串转换为整数,简便函数 Atoin2, _ := 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 mainimport ("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():执行命令并获取标准输出和标准错误输出,如果命令执行失败,则返回错误。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/51380.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

告别数字化系统“物理叠加”,华为云推动智慧门店价值跃迁

文|智能相对论 作者|叶远风 有大屏幕滚动播放广告&#xff1b; 有人脸识别系统让消费者自助结账&#xff1b; 有订单管理系统综合分析一段时间内总体经营情况&#xff1b; 有全门店监控直连总部机房&#xff1b; …… 以搭载数字化系统的硬件设备为表面特征的智慧门店&a…

更改Docker的存储位置

要更改Docker的存储位置&#xff0c;可以按照以下步骤进行操作 文章目录 停止Docker服务编辑Docker配置文件 /etc/docker/daemon.json保存并关闭配置文件,并服务程序配置文件生效移动现有的Docker数据目录到新的存储路径更新文件权限以确保Docker可以访问新的数据目录启动Dock…

Windows快速关闭占用某端口的进程

在Windows操作系统中&#xff0c;你可以使用以下方法来快速关闭占用特定端口的进程&#xff0c;比如端口8848&#xff1a; 使用命令行工具 打开命令提示符&#xff08;Command Prompt&#xff09;。 输入以下命令&#xff0c;将端口号替换为你需要关闭的端口&#xff08;例如…

Java项目时间字段问题-MySQL

Java项目时间字段问题-MySQL ​ 在 Java 项目中&#xff0c;与 MySQL 数据库中的时间字段对应的 Java 类型通常使用 java.time 包中的类&#xff0c;这是从 Java 8 开始引入的日期和时间 API。以下是常见的时间字段和它们在 Java 实体类中的对应类型示例&#xff1a; 1、DATE…

前端面试:【性能优化】前端缓存、CDN、懒加载和预加载

亲爱的前端开发者&#xff0c;Web性能对用户体验至关重要。如果你想让你的网站更快、更具吸引力&#xff0c;就需要关注前端性能优化。在这篇文章中&#xff0c;我们将深入探讨四个关键的性能优化策略&#xff1a;前端缓存、CDN&#xff08;内容分发网络&#xff09;、懒加载和…

按软件开发阶段的角度划分:单元测试、集成测试、系统测试、验收测试

1.单元测试&#xff08;Unit Testing&#xff09; 单元测试&#xff0c;又称模块测试。对软件的组成单位进行测试&#xff0c;其目的是检验软件基本组成单位的正确性。测试的对象是软件里测试的最小单位&#xff1a;模块。 测试阶段&#xff1a;编码后或者编码前&#xff08;…

Unity OnDrawGizmos的简单应用 绘制圆形

编辑器和配置表各有各的好。 卡牌游戏即使再复杂&#xff0c;哪怕是梦幻西游&#xff0c;大话西游那种&#xff0c;甚至wow那种&#xff0c;用配表都完全没问题。但是崩坏3&#xff0c;或者鬼泣&#xff0c;格斗游戏&#xff0c;可视化编辑器是唯一的选择。 开发初期刚开始配技…

人工智能技术

人工智能技术是什么&#xff1f; 人工智能技术&#xff08;Artificial Intelligence Technology&#xff0c;AI技术&#xff09;是一种模仿人类智能和思维方式的计算机技术&#xff0c;旨在使计算机能够执行需要人类智能才能完成的任务。这些任务包括理解自然语言、解决问题、…

高手进阶之路---pyqt自定义信号

高手进阶之路—pyqt自定义信号 1.思考问题为什么要自定义信号&#xff0c;qt5本身已有信号槽函数 # pushButton 被clicked的时候connect 函数print self.pushButton.clicked.connect(self.print)def print(self):print("我被点击了")或者使用 # 需要引入 pyqtSlo…

ubuntu20.04 编译安装运行emqx

文章目录 安装依赖编译运行登录dashboard压力测试 安装依赖 Erlang/OTP OTP 24 或 25 版本 apt-get install libncurses5-dev sudo apt-get install erlang如果安装的erlang版本小于24的话&#xff0c;可以使用如下方法自行编译erlang 1.源码获取 wget https://github.com/erla…

微服务中间件--多级缓存

多级缓存 多级缓存a.JVM进程缓存1) Caffeine2) 案例 b.Lua语法1) 变量和循环2) 条件控制、函数 c.多级缓存1) 安装OpenResty2) 请求参数处理3) 查询Tomcat4) Redis缓存预热5) 查询Redis缓存6) Nginx本地缓存 d.缓存同步1) 数据同步策略2) 安装Canal2.a) 开启MySQL主从2.b) 安装…

mysql(八)事务隔离级别及加锁流程详解

目录 MySQL 锁简介什么是锁锁的作用锁的种类共享排他锁共享锁排它锁 粒度锁全局锁表级锁页级锁行级锁种类 意向锁间隙临键记录锁记录锁间隙锁 加锁的流程锁的内存结构加锁的基本流程根据主键加锁根据二级索引加锁根据非索引字段查询加锁加锁规律 锁信息查看查看锁的sql语句 数据…

龙迅LT7911UX TYPE-C/DP转MIPI/LVDS,内有HDCP

1. 描述 LT7911UX是一种高性能的Type-C/DP1.4a到MIPI或LVDS芯片。HDCP RX作为HDCP中继器的上游端&#xff0c;可以与其他芯片的HDCP TX协同工作&#xff0c;实现中继器的功能。 对于DP1.4a输入&#xff0c;LT7911UX可以配置为1/2/4车道。自适应均衡使其适用于长电缆应用&#…

bash: conda: command not found

问题描述&#xff1a; 在Pycharm上用SSH远程连接到服务器&#xff0c;打开Terminal准备查看用 conda 创建的虚拟环境时&#xff0c;却发现调用 conda 指令时出现以下报错&#xff1a; -bash: conda: command not found如果使用Xshell 利用端口号直接连接该 docker 容器&#…

zhm_real/MotionPlanning运动规划库中A*算法源码详细解读

本文主要对zhm_real/MotionPlanning运动规划库中A*算法源码进行详细解读&#xff0c;即对astar.py文件中的内容进行详细的解读&#xff0c;另外本文是 Hybrid A * 算法源码解读的前置文章&#xff0c;为后续解读Hybrid A * 算法源码做铺垫。 astar.py文件中的源码如下&#xff…

Matlab高光谱遥感数据处理与混合像元分解实践技术

光谱和图像是人们观察世界的两种方式&#xff0c;高光谱遥感通过“图谱合一”的技术创新将两者结合起来&#xff0c;大大提高了人们对客观世界的认知能力&#xff0c;本来在宽波段遥感中不可探测的物质&#xff0c;在高光谱遥感中能被探测。以高光谱遥感为核心&#xff0c;构建…

Qt中XML文件创建及解析

一 环境部署 QT的配置文件中添加xml选项&#xff1a; 二 写入xml文件 头文件&#xff1a;#include <QXmlStreamWriter> bool MyXML::writeToXMLFile() {QString currentTime QDateTime::currentDateTime().toString("yyyyMMddhhmmss");QString fileName &…

Redis之bitmap类型解读

目录 基本介绍 基本命令 Setbit Getbit BITCOUNT 应用场景 统计当日活跃用户 用户签到 bitmap - Redis布隆过滤器 &#xff08;应对缓存穿透问题&#xff09; 基本介绍 Redis 的位图&#xff08;bitmap&#xff09;是由多个二进制位组成的数组&#xff0c;只有两…

opencv 文档识别+UI界面识别系统

目录 一、实现和完整UI视频效果展示 主界面&#xff1a; 识别结果界面&#xff1a; 查看处理图片过程&#xff1a; 查看历史记录界面&#xff1a; 二、原理介绍&#xff1a; 将图像变换大小->灰度化->高斯滤波->边缘检测 轮廓提取 筛选第三步中的轮廓&#xf…

Microsoft Excel整合Python:数据分析的新纪元

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…