当前位置: 首页 > news >正文

走进 Go 语言基础语法

目录

1. Go 语言的 Hello World 

2. 变量 

3. if else 

4. 循环 

5. switch 

6. 数组  

7. 切片 

8. map 

9. range 

10. 函数 

11. 指针 

12. 结构体 

13. 结构体方法

14. 错误处理 

15. 字符串操作 

16. 字符串格式化 

17. JSON处理 

18. 时间处理 

19. 数字解析

20. 进程信息 


1. Go 语言的 Hello World 

package mainimport "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关键字:

package mainimport "fmt"func main() {// Go 语言会对声明的变量进行初始化var a int    //整数类型的零值是 0var b string //字符串类型的零值是""var c bool   //布尔类型的零值是falsefmt.Println(a, b, c)
}

也可以同时声明多个变量或在声明变量时指定初始值:

func main() {//同时声明多个变量var d, e intfmt.Println(d, e) // 0 0//在声明变量时指定初始值var f int = 10fmt.Println(f) //10
}

GO语言中使用var关键字声明变量,支持自动推导变量的类型:[ 重点 ]

func main() {var a = "字符串"var b = 10var c = truefmt.Println(a, b, c)  //字符串 10 true
}

变量的简短声明:

Go 语言还支持简短声明变量,使用 := 操作符。例如:

func main() {a := 10b, c := true, "字符串"fmt.Println(a, b, c) //10 true 字符串
}

a := 10,这种方式声明并初始化了变量a,它会自动根据赋值的类型来推断变量的类型。这里a被推断为整数类型。但是简短声明只能在函数内部使用

同样可以使用简短声明来同时声明多个变量。

变量的类型转换:

func main() {a := 10b := float64(a) //将a转为浮点数赋给bfmt.Println(b)
}

常量的定义:

使用const关键字来定义常量:

const name = "小林"func main() {fmt.Println(name)
}

如果一组常量的类型相同,还可以省略类型声明。例如:const A, B = 1, 2 Go 语言会自动根据赋值来推断常量的类型,这里AB都被推断为整数类型。

3. if else 

go语言中 if 语句后没有括号,若将条件判断语句写在括号中,运行代码时编译器会自动去掉括号:

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循环后面跟的条件同样也是不带括号的。

func main() {//for后没有条件 为死循环for {fmt.Println("loop")break}//打印0~9 (写法1)for j := 0; j < 10; j++ {fmt.Println(j)}//打印0~9 (写法2)i := 0for i <= 9 {fmt.Println(i)i = i + 1}
}

5. switch 

同样,switch后变量名不加括号:

func main() {a := 2switch a {case 1:fmt.Println("one")case 2:fmt.Println("two") //输出twocase 3:fmt.Println("three")case 4, 5:fmt.Println("four or five")default:fmt.Println("other")}
}

6. 数组  

数组的声明:

func main() {//通过var声明var a [5]inta[2] = 2fmt.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函数创建:

func main() {//创建一个长度为3的字符切片。s := make([]string, 3)s[0] = "a"s[1] = "b"s[2] = "c"fmt.Println("get:", s[2])   // cfmt.Println("len:", len(s)) // 3
}

操作方法

追加元素:

使用append函数可以向切片中追加一个或多个元素,如果切片的容量不足,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函数可以将一个切片的内容复制到另一个切片中。

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]
}

切片的切片:

可以从一个切片中再创建一个子切片,子切片与原切片共享底层数组。

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函数

func main() {m := make(map[string]int)m["one"] = 1m["two"] = 2fmt.Println(m)           // map[one:1 two:2]fmt.Println(len(m))      // 2fmt.Println(m["one"])    // 1fmt.Println(m["unknow"]) // 0
}

创建方式1:使用字面量创建

	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]

  删除键值对:

func main() {m := make(map[string]int)m["one"] = 1m["two"] = 2m["three"] = 3fmt.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)的关键字。它提供了一种简洁的方式来遍历这些数据结构中的元素。

func main() {m := make(map[string]int)m["one"] = 1m["two"] = 2m["three"] = 3//使用range遍历mapfor k, v := range m {fmt.Println(k, v)}
}

10. 函数 

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
}

实际的业务逻辑代码中,几乎所有的函数都返回多个值,第一个值是真正的返回结果,第二个值是错误信息。例如:

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中支持的操作非常有限,这里的主要用途就是对传入的参数进行修改

//无效
func add2(n int) {n += 2
}
//有效
func add2ptr(n *int) {*n += 2
}func main() {n := 5add2(n)fmt.Println(n) // 5add2ptr(&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是一种用户自定义的数据类型,用于将多个不同类型的字段组合在一起,以表示一个复杂的数据结构。

	type student struct {name stringage intgender string}

结构体实例化 

1. 基本实例化

func main() {type student struct {name   stringage    intgender string}s := student{"小谷", 20, "男"} // {小谷 20 男}fmt.Println(s)
}

2. 指定字段初始化

func main() {type student struct {name   stringage    intgender string}s := student{name: "小谷", gender: "男"}fmt.Println(s) // {小谷 0 男}
}

没有被指定初始化的字段,会被自动初始化为其类型的零值。

3. 使用new函数实例化  (有点Java的味道了)

package mainimport "fmt"func main() {type student struct {name   stringage    intgender string}//使用new函数实例化s := new(student)s.name = "小谷"s.age = 20s.gender = "男"fmt.Println(s.name, s.age, s.gender) // 小谷 20 男
}
  • new函数用于创建一个指定类型的指针。对于结构体,它会返回一个指向结构体的指针。
  • 这里new(student)创建了一个student结构体的指针,然后通过指针访问其字段并赋值。

结构体的比较

如果结构体的所有字段都是可比较的,那么这个结构体也是可比较的:

type Point struct {X intY 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")}
}

如果结构体包含不可比较的字段(如mapslice等引用类型),那么这个结构体是不可比较的。如果尝试比较这样的结构体,会导致编译错误。

13. 结构体方法

package mainimport "fmt"type user struct {name     stringpassword 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类型是一个接口,定义如下:

type error interface {Error() string
}

这意味着任何实现了Error()方法并返回一个字符串的类型都满足error接口。当函数执行出现问题时,会返回一个非nilerror值来告知调用者错误信息。

简单的错误处理示例:

package mainimport ("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函数会返回一个非nilerr(在文件操作中,os.Open函数用于打开一个文件,它返回一个文件指针和一个error值),通过检查err!= nil来判断是否出现错误。如果有错误,就打印错误信息并终止程序的执行;如果没有错误,就可以正常处理文件,并且使用defer关键字确保文件最终会被关闭。

案例二: 

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() {u, err := findUser([]user{{"wang", "2279"}}, "wang")if err != nil {fmt.Println(err)return}fmt.Println(u.name) // wangif u, err := findUser([]user{{"wang", "2279"}}, "zhang"); err != nil {fmt.Println(err) // not foundreturn} else {fmt.Println(u.name)}
}

15. 字符串操作 

在标准库strings包中有许多字符串工具函数:

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//字符替换 ,-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是最常用的字符串格式化函数之一。例如,将一个整数和一个字符串格式化为一个新的字符串:

package mainimport ("fmt"
)func main() {age := 20name := "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:用于格式化指针的值,以十六进制形式输出。例如,对于一个指针变量pfmt.Sprintf("%p", p)会返回指针的十六进制表示。

 在golang中还可以用%v来打印任意类型的变量

type point struct {x, y int
}func main() {s := "hello"n := 123p := point{1, 2}fmt.Println(s, n) // hello 123fmt.Println(p)    // {1 2}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}
}

%v    只打印值

%+v  打印字段的名字和值 (对于结构体类型)

%#v  它比%+v更加详细,包含了结构体的包名(main)、结构体类型名(Point)以及字段名称和值

17. JSON处理 

对于已有的结构体,保证其每个字段首字母大写,那么这个结构体就能用 json.Marshal 序列化,序列化后生成一个 buf数组(可以理解为一个字符串)

package mainimport ("encoding/json""fmt"
)type userInfo struct {Name  stringAge   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 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"}}
}

18. 时间处理 

在 Go 语言中,可以使用time.Now()函数来获取当前的时间。这个函数返回一个time.Time类型的值,它包含了年、月、日、时、分、秒、纳秒以及时区等信息。

时间戳的概念:时间戳是从 1970 年 1 月 1 日 UTC 到指定时间所经过的秒数。在 Go 语言中,可以使用Unix()方法来获取时间戳。 

package mainimport ("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. 数字解析

package mainimport ("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. 进程信息 

package mainimport ("fmt""os""os/exec"
)func main() {// go run example/20-env/main.go a b c dfmt.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   欢迎大家与我交流!


http://www.mrgr.cn/news/67643.html

相关文章:

  • 神经网络基础--什么是神经网络?? 常用激活函数是什么???
  • opencv - py_imgproc - py_grabcut GrabCut 算法提取前景
  • Spring挖掘:(AOP篇)
  • Halcon 从XML中读取配置参数
  • 5G NR物理层|5G PHY层概述
  • 数据仓库之 Atlas 血缘分析:揭示数据流奥秘
  • SAP固定资产报废BAPI_ASSET_RETIREMENT_POST的主要参数说明<转载>
  • 电能管理系统(源码+文档+部署+讲解)
  • 6项!国自然基金委员会拟批准资助项目名单公布!
  • 计算机信息安全
  • 解密.Lockbit3.0勒索病毒:恢复加密数据与预防策略
  • 基于电力需求侧能效管理平台的建设及应用
  • 数据集收集器0.3
  • 代码随想录算法训练营Day55 | 图论理论基础、深度优先搜索理论基础、卡玛网 98.所有可达路径、797. 所有可能的路径、广度优先搜索理论基础
  • 魅力标签云,奇幻词云图 —— 数据可视化新境界
  • 新书速览|C++编程之禅:从理论到实践
  • springboot 之 接口数据脱敏
  • 想转行做大模型?AI产品经理转行必读指南
  • 牵手APP引领交友新风尚,多元匹配助力寻找心仪伴侣
  • #渗透测试#SRC漏洞挖掘# 操作系统-Linux系统基础06之ssh服务、history
  • 在Ubuntu下安装RabbitMQ、添加一个新的登录用户并设置密码
  • 使用Python将EPUB电子书网文主角换成自己
  • .baxia勒索病毒来袭:数据恢复与防护措施详解
  • 【提效工具开发】Python功能模块执行和 SQL 执行 需求整理
  • 【C#】创建一个主菜单和弹出菜单系统
  • 归并排序:高效算法的深度解析