目录
[1. Go 语言的 Hello World](#1. Go 语言的 Hello World)
[2. 变量](#2. 变量)
[3. if else](#3. if else)
[4. 循环](#4. 循环)
[5. switch](#5. switch)
[6. 数组](#6. 数组)
[7. 切片](#7. 切片)
[8. map](#8. map)
[9. range](#9. range)
[10. 函数](#10. 函数)
[11. 指针](#11. 指针)
[12. 结构体](#12. 结构体)
[13. 结构体方法](#13. 结构体方法)
[14. 错误处理](#14. 错误处理)
[15. 字符串操作](#15. 字符串操作)
[16. 字符串格式化](#16. 字符串格式化)
[17. JSON处理](#17. JSON处理)
[18. 时间处理](#18. 时间处理)
[19. 数字解析](#19. 数字解析)
[20. 进程信息](#20. 进程信息)
1. Go 语言的 Hello World
Go
package main
import "fmt"
func main() {
fmt.Println("hello world")
}
代码解读:
-
package main:
这是 Go 语言程序的包声明。每个 Go 程序都必须属于一个包,**
main
**包是一个特殊的包,它定义了一个可独立执行的程序。 -
import "fmt":
导入了**
fmt
** 包,fmt
包提供了格式化输入输出的函数。在这个程序中,我们将使用**fmt.Println
**函数来输出内容。 -
func main():
这是程序的入口点,每个可独立执行的 Go 程序都必须有一个**
main
** 函数。**main
**函数不接受任何参数,也不返回任何值。 -
fmt.Println("hello world"):
调用**
fmt
** 包中的**Println
**函数,该函数用于在控制台打印输出内容,并在输出后自动添加一个换行符。这里输出的内容是 "hello world" 字符串。
2. 变量
变量声明:
在go语言中,最基本的方式是使用**var
**关键字:
Go
package main
import "fmt"
func main() {
// Go 语言会对声明的变量进行初始化
var a int //整数类型的零值是 0
var b string //字符串类型的零值是""
var c bool //布尔类型的零值是false
fmt.Println(a, b, c)
}
也可以同时声明多个变量或在声明变量时指定初始值:
Go
func main() {
//同时声明多个变量
var d, e int
fmt.Println(d, e) // 0 0
//在声明变量时指定初始值
var f int = 10
fmt.Println(f) //10
}
GO语言中使用var关键字声明变量,支持自动推导变量的类型:[ 重点 ]
Go
func main() {
var a = "字符串"
var b = 10
var c = true
fmt.Println(a, b, c) //字符串 10 true
}
变量的简短声明:
Go 语言还支持简短声明变量,使用 := 操作符。例如:
Go
func main() {
a := 10
b, c := true, "字符串"
fmt.Println(a, b, c) //10 true 字符串
}
a := 10
,这种方式声明并初始化了变量a,它会自动根据赋值的类型来推断变量的类型。这里a被推断为整数类型。但是简短声明只能在函数内部使用。
同样可以使用简短声明来同时声明多个变量。
变量的类型转换:
Go
func main() {
a := 10
b := float64(a) //将a转为浮点数赋给b
fmt.Println(b)
}
常量的定义:
使用**const
**关键字来定义常量:
Go
const name = "小林"
func main() {
fmt.Println(name)
}
如果一组常量的类型相同,还可以省略类型声明。例如:const A, B = 1, 2
Go 语言会自动根据赋值来推断常量的类型,这里**A
** 和**B
**都被推断为整数类型。
3. if else
go语言中 if 语句后没有括号,若将条件判断语句写在括号中,运行代码时编译器会自动去掉括号:
Go
func main() {
if 8%4 == 0 {
fmt.Println("8 is divisible by 4")
}
}
Go语言中 if 后必须跟{ },不能像C/C++ 一样与 if 语句写在同一行。
4. 循环
Go语言中没有while循环和do-while循环,只有for循环一种。且for循环后面跟的条件同样也是不带括号的。
Go
func main() {
//for后没有条件 为死循环
for {
fmt.Println("loop")
break
}
//打印0~9 (写法1)
for j := 0; j < 10; j++ {
fmt.Println(j)
}
//打印0~9 (写法2)
i := 0
for i <= 9 {
fmt.Println(i)
i = i + 1
}
}
5. switch
同样,switch后变量名不加括号:
Go
func main() {
a := 2
switch a {
case 1:
fmt.Println("one")
case 2:
fmt.Println("two") //输出two
case 3:
fmt.Println("three")
case 4, 5:
fmt.Println("four or five")
default:
fmt.Println("other")
}
}
6. 数组
数组的声明:
Go
func main() {
//通过var声明
var a [5]int
a[2] = 2
fmt.Println(a) //[0 0 2 0 0]
//通过len获取数组长度
fmt.Println(len(a)) // 5
//简短声明
b := [5]int{1, 2, 3}
fmt.Println(b) //[1 2 3 0 0]
}
在实际开发过程中其实很少使用到数组,因为它的长度是固定的 ,更多时候是使用切片。
7. 切片
切片它是一个可变长度的数组,切片有三个重要的属性:指针 、长度 和容量。
使用**make
**函数创建:
Go
func main() {
//创建一个长度为3的字符切片。
s := make([]string, 3)
s[0] = "a"
s[1] = "b"
s[2] = "c"
fmt.Println("get:", s[2]) // c
fmt.Println("len:", len(s)) // 3
}
操作方法
追加元素:
使用append 函数可以向切片中追加一个或多个元素,如果切片的容量不足,Go 会自动创建一个新的底层数组,并将原切片的内容复制到新数组中。
Go
func main() {
//创建一个长度为3的字符切片。
s := make([]string, 3)
s[0] = "a"
s[1] = "b"
s[2] = "c"
//追加元素
s = append(s, "d", "e", "f")
fmt.Println(s) // [a b c d e f]
}
复制切片:
使用copy 函数可以将一个切片的内容复制到另一个切片中。
Go
func main() {
//创建一个长度为3的字符切片。
s := make([]string, 3)
s[0] = "a"
s[1] = "b"
s[2] = "c"
//追加元素
s = append(s, "d", "e", "f")
fmt.Println(s) // [a b c d e f]
//复制切片
c := make([]string, len(s))
copy(c, s) //将s切片的内容复制到c切片中
fmt.Println(c) // [a b c d e f]
}
切片的切片:
可以从一个切片中再创建一个子切片,子切片与原切片共享底层数组。
Go
func main() {
//创建一个长度为6的字符切片。
s := make([]string, 6)
s[0] = "a"
s[1] = "b"
s[2] = "c"
s[3] = "d"
s[4] = "e"
s[5] = "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]
}
8. map
在 Go 语言中,map
是一种无序的键值对集合。它的主要作用是可以根据键(key
)快速地查找对应的值(value
)。map
的键是唯一的,在同一个**map
**中不能有两个相同的键。
创建方式1:通过make函数
Go
func main() {
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
fmt.Println(m["unknow"]) // 0
}
创建方式1:使用字面量创建
Go
m2 := map[string]int{"one": 1, "two": 2}
var m3 = map[string]int{"one": 1, "two": 2}
fmt.Println(m2, m3) // map[one:1 two:2] map[one:1 two:2]
删除键值对:
Go
func main() {
m := make(map[string]int)
m["one"] = 1
m["two"] = 2
m["three"] = 3
fmt.Println(m) // map[one:1 three:3 two:2]
//删除键值对
delete(m, "one")
fmt.Println(m) // map[three:3 two:2]
}
**特别注意:**Go中的map是完全无序的,遍历的时候不会按字母顺序或插入顺序输出
9. range
在 Go 语言中,range
是一个用于遍历各种数据结构(如切片、数组、字符串、映射map
)的关键字。它提供了一种简洁的方式来遍历这些数据结构中的元素。
Go
func main() {
m := make(map[string]int)
m["one"] = 1
m["two"] = 2
m["three"] = 3
//使用range遍历map
for k, v := range m {
fmt.Println(k, v)
}
}
10. 函数
Go
func add(a int, b int) int {
return a + b
}
/*
func add(a, b int) int {
return a + b
}
*/
func main() {
res := add(1, 2)
fmt.Println(res) // 3
}
实际的业务逻辑代码中,几乎所有的函数都返回多个值,第一个值是真正的返回结果,第二个值是错误信息。例如:
Go
func exists(m map[string]string, k string) (v string, ok bool) {
v, ok = m[k]
return v, ok
}
该函数返回第一个值v,也就是真正的value,返回第二个值ok,也就是判断是否存在
11. 指针
相比于C/C++里的指针,golang中支持的操作非常有限,这里的主要用途就是对传入的参数进行修改,
Go
//无效
func add2(n int) {
n += 2
}
//有效
func add2ptr(n *int) {
*n += 2
}
func main() {
n := 5
add2(n)
fmt.Println(n) // 5
add2ptr(&n)
fmt.Println(n) // 7
}
- 在add2 函数中,接受了一个整数参数
n
,并将其值加 2。但是由于 Go 语言是值传递,n += 2
只是修改了函数内部局部变量n
的值,不会影响到函数外部调用处的变量。所以这个函数对传入的参数的修改不会影响到原始变量。所以在**main
** 函数中调用**add2(n)
** 后,**n
**的值仍然是 5 。 - 在 add2ptr 函数中,接受一个整数指针参数
n
,通过解引用指针修改其所指向的值,将其值加 2。在**main
** 函数中调用add2ptr(&n)
后,由于是通过指针修改了原始变量的值,所以n
的值变为 7。
在 Go 语言中,函数参数可以是值传递或指针传递。值传递会创建参数的副本,对副本的修改不会影响到原始值;而指针传递允许函数直接修改调用者的变量,因为它们共享相同的内存地址。
12. 结构体
在 Go 语言中,结构体 **(struct
)**是一种用户自定义的数据类型,用于将多个不同类型的字段组合在一起,以表示一个复杂的数据结构。
Go
type student struct {
name string
age int
gender string
}
结构体实例化
- 基本实例化
Go
func main() {
type student struct {
name string
age int
gender string
}
s := student{"小谷", 20, "男"} // {小谷 20 男}
fmt.Println(s)
}
- 指定字段初始化
Go
func main() {
type student struct {
name string
age int
gender string
}
s := student{name: "小谷", gender: "男"}
fmt.Println(s) // {小谷 0 男}
}
没有被指定初始化的字段,会被自动初始化为其类型的零值。
- 使用new函数实例化 (有点Java的味道了)
Go
package main
import "fmt"
func main() {
type student struct {
name string
age int
gender string
}
//使用new函数实例化
s := new(student)
s.name = "小谷"
s.age = 20
s.gender = "男"
fmt.Println(s.name, s.age, s.gender) // 小谷 20 男
}
- **
new
**函数用于创建一个指定类型的指针。对于结构体,它会返回一个指向结构体的指针。 - 这里**
new(student)
** 创建了一个**student
**结构体的指针,然后通过指针访问其字段并赋值。
结构体的比较
如果结构体的所有字段都是可比较的,那么这个结构体也是可比较的:
Go
type Point struct {
X int
Y int
}
func main() {
p1 := Point{1, 2}
p2 := Point{1, 2}
if p1 == p2 {
fmt.Println("p1 and p2 are equal") // p1 and p2 are equal
} else {
fmt.Println("p1 and p2 are not equal")
}
}
如果结构体包含不可比较的字段(如map、slice 等引用类型),那么这个结构体是不可比较的。如果尝试比较这样的结构体,会导致编译错误。
13. 结构体方法
Go
package main
import "fmt"
type user struct {
name string
password string
}
func (u user) checkPassword(password string) bool {
return u.password == password
}
func (u *user) resetPassword(password string) {
u.password = password
}
func main() {
a := user{name: "wang", password: "1024"}
a.resetPassword("2048")
fmt.Println(a.checkPassword("2048")) // true
}
14. 错误处理
基础概念:
在 Go 语言中,错误处理是构建健壮程序的重要部分。Go 语言没有像其他一些语言那样的异常机制,而是使用返回值来表示错误。大部分可能出现错误的函数都会返回一个error 类型的值,这个**error
**类型是一个接口,定义如下:
Go
type error interface {
Error() string
}
这意味着任何实现了**Error()
** 方法并返回一个字符串的类型都满足**error
** 接口**。当函数执行出现问题时,会返回一个非nil
的error
值来告知调用者错误信息。**
简单的错误处理示例:
Go
package main
import (
"fmt"
"os"
)
func main() {
file, err := os.Open("nonexistent_file.txt")
if err!= nil {
fmt.Println("Error opening file:", err)
return
}
// 正常处理文件
defer file.Close()
}
这里尝试打开一个不存在的文件,os.Open
函数会返回一个非**nil
** 的**err
** 值(在文件操作中,os.Open
函数用于打开一个文件,它返回一个文件指针和一个**error
值),通过检查err!= nil
** 来判断是否出现错误。如果有错误,就打印错误信息并终止程序的执行;如果没有错误,就可以正常处理文件,并且使用**defer
**关键字确保文件最终会被关闭。
案例二:
Go
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() {
u, err := findUser([]user{{"wang", "2279"}}, "wang")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(u.name) // wang
if u, err := findUser([]user{{"wang", "2279"}}, "zhang"); err != nil {
fmt.Println(err) // not found
return
} else {
fmt.Println(u.name)
}
}
15. 字符串操作
在标准库strings包中有许多字符串工具函数:
Go
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
//字符替换 ,-1表示进行无限制的替换 即替换所有匹配的字符
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
}
16. 字符串格式化
在go语言的 fmt 包中有许多字符串格式化的方法,常用的有:
fmt.Sprintf函数:
在 Go 语言中,**fmt.Sprintf
**是最常用的字符串格式化函数之一。例如,将一个整数和一个字符串格式化为一个新的字符串:
Go
package main
import (
"fmt"
)
func main() {
age := 20
name := "WenHui"
result := fmt.Sprintf("My name is %s and I am %d years old.", name, age)
fmt.Println(result) // My name is WenHui and I am 20 years old.
}
这里**%s
** 是用于格式化字符串的占位符,它会被**name
** 变量的值替换;%d
是用于格式化整数的占位符,会被**age
** 变量的值替换。 (和C语言一样)
格式化占位符的类型:
- 整数类型
%d
:用于格式化十进制整数。例如,fmt.Sprintf("%d", 10)
会返回"10"
。%b
:用于格式化二进制整数。如fmt.Sprintf("%b", 10)
会返回"1010"
。%o
:用于格式化八进制整数,fmt.Sprintf("%o", 10)
返回"12"
。%x
和%X
:用于格式化十六进制整数,%x
返回小写字母表示的十六进制数,%X
返回大写字母表示的十六进制数。例如,fmt.Sprintf("%x", 10)
返回"a"
,fmt.Sprintf("%X", 10)
返回"A"
。- 浮点数类型
%f
:用于格式化十进制浮点数。例如,fmt.Sprintf("%f", 3.14)
会返回"3.140000"
。可以通过指定精度来控制小数点后的位数,如fmt.Sprintf("%.2f", 3.14)
会返回"3.14"
。- 字符串类型
%s
:用于格式化字符串,如前面例子所示。%q
:用于将字符串用双引号引起来并进行转义。例如,fmt.Sprintf("%q", "hello")
返回""hello""
,如果字符串中有特殊字符,会进行相应的转义。- 布尔类型
%t
:用于格式化布尔值。例如,fmt.Sprintf("%t", true)
返回"true"
,- 指针类型
%p
:用于格式化指针的值,以十六进制形式输出。例如,对于一个指针变量p
,fmt.Sprintf("%p", p)
会返回指针的十六进制表示。
在golang中还可以用%v来打印任意类型的变量
Go
type point struct {
x, y int
}
func main() {
s := "hello"
n := 123
p := point{1, 2}
fmt.Println(s, n) // hello 123
fmt.Println(p) // {1 2}
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}
}
%v 只打印值
%+v 打印字段的名字和值 (对于结构体类型)
%#v 它比
%+v
更加详细,包含了结构体的包名(main
)、结构体类型名(Point
)以及字段名称和值
17. JSON处理
对于已有的结构体,保证其每个字段首字母大写,那么这个结构体就能用 json.Marshal 序列化,序列化后生成一个 buf数组(可以理解为一个字符串)
Go
package main
import (
"encoding/json"
"fmt"
)
type userInfo struct {
Name string
Age int `json:"age"`
Hobby []string
}
func main() {
a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "TypeScript"}}
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,"Hobby":["Golang","TypeScript"]}
buf, err = json.MarshalIndent(a, "", "\t")
if err != nil {
panic(err)
}
fmt.Println(string(buf))
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"}}
}
18. 时间处理
在 Go 语言中,可以使用**time.Now()
** 函数来获取当前的时间。这个函数返回一个**time.Time
**类型的值,它包含了年、月、日、时、分、秒、纳秒以及时区等信息。
时间戳的概念:时间戳是从 1970 年 1 月 1 日 UTC 到指定时间所经过的秒数。在 Go 语言中,可以使用**Unix()
**方法来获取时间戳。
Go
package main
import (
"fmt"
"time"
)
func main() {
//获取当前时间
now := time.Now()
fmt.Println("当前时间:", now) // 2024-11-04 13:35:48.1742921 +0800 CST m=+0.000000001
//时间格式化
formattedTime := now.Format("2006-01-02 15:04:05")
fmt.Println("格式化后的时间:", formattedTime) // 2024-11-04 13:35:48
//获取时间戳
timestamp := now.Unix()
fmt.Println("当前时间戳:", timestamp) // 1730698548
//从时间戳转换为时间
timeFromTimestamp := time.Unix(timestamp, 0)
fmt.Println("从时间戳转换后的时间:", timeFromTimestamp) //2024-11-04 13:35:48 +0800 CST
//时间计算
newTime := now.Add(24 * time.Hour)
fmt.Println("新的时间:",newTime) //2024-11-05 13:35:48.1742921 +0800 CST m=+86400.000000001
}
19. 数字解析
Go
package main
import (
"fmt"
"strconv"
)
func main() {
//将字符串转为整数
n, _ := strconv.Atoi("521")
fmt.Println(n) // 521
//将字符串解析为浮点数(float64)
f, _ := strconv.ParseFloat("3.14", 64)
fmt.Println(f) // 3.14
//将字符串 "1314" 按照十进制(基数为 10)解析为 int64 类型的整数
n1, _ := strconv.ParseInt("1314", 10, 64)
fmt.Println(n1) // 1314
//整数转字符串
str := strconv.Itoa(123)
fmt.Println(str) //123
}
20. 进程信息
Go
package main
import (
"fmt"
"os"
"os/exec"
)
func main() {
// go run example/20-env/main.go a b c d
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")) // /usr/local/go/bin...
fmt.Println(os.Setenv("AA", "BB"))
buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput()
if err != nil {
panic(err)
}
fmt.Println(string(buf)) // 127.0.0.1 localhost
}
🌸🌸🌸 完结撒花🌸🌸🌸
博主WX:++g2279605572++ 欢迎大家与我交流!