Go语言入门指南
1.Go程序的组成
每个 Go 程序都由包构成。
程序从 main 包开始运行。
一段基本的go程序包括以下几部分:
- 包声明:
package main表示这是一个可执行的程序。 - 导入包: 使用圆括号导入多个包
- main程序: 这是程序的主函数。所有Go程序的执行都是在这里开始的。
以下是一段示例代码:
package main
import "fmt"
func main(){
fmt.Println("Hello world!")
}
2.变量声明
Go语言中使用var,程序会自己识别变量的类型,或者使用var parameter type = value来指定形式。Go还支持使用:=来声明变量。
3.for,if-else,switch
for循环区别于Java语言的地方在于,Go中的for循环不用带判断条件的括号,只需要直接写出条件即可。但必须要带上大括号。对于if-else语句,可以在if中赋值,以分号结尾,然后在进行if语句判断condition
对于Go中的switch语句,无需写break语句,在执行到这一case下的语句后,会直接退出
package main
import (
"fmt"
)
func main(){
a := 2
switch a{
//可以像if那样写: switch a := 2;a{}
case 1:
fmt.Println(a)
case 2:
fmt.Println("two")
case 3:
fmt.Println("three")
default:
fmt.Println("other")
}
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("It's before noon")
default:
fmt.Println("It's after noon")
}
}
4.数组
声明方式:
方式一:var a[5] int
方式二: b := [5]int{1,2,3,4,5}
5.slice和range
对slice的介绍:
切片(Slices)是Go语言中非常强大且灵活的数据结构,用于处理动态大小的序列。与数组相比,切片在长度和容量上更加灵活,且具有丰富的内置函数支持。
声明方式:s := make([]type,len),其中type为变量类型,len为切片长度
关于make的使用:make 函数用于分配和初始化切片、映射和通道。对于切片,make 函数接受三个参数:
- 类型:切片的元素类型。
- 长度:切片的初始长度。
- 容量(可选):切片的初始容量。如果省略,容量将与长度相同。
Go中的切片与Python中的切片相同,遵循左闭右开区间 [start, end),即包含起始索引但不包含结束索引。
注意:切片本身是不可变的引用类型,不能直接修改切片的指针、长度或容量。但可以通过重新赋值来创建新的切片。
对range的介绍:
range是Go语言中用于迭代数据结构的关键字,通常与for循环结合使用。它能够返回集合中每个元素的索引和值,简化了遍历操作。range可以应用于数组、切片、映射、字符串以及通道,使得对这些数据结构的遍历更加简洁和高效。
基本语法如下:for key, value := range collection { }
range还支持只获取索引或值,使用_(占位符)即可。
6.defer
defer是Go语言中的一个关键字,用于在函数返回之前执行指定的函数。通过defer,开发者可以确保在函数执行完毕时,某些清理操作必定会被执行,无论函数是正常返回还是因为错误提前退出。
defer 语句会将函数推迟到外层函数返回之后执行。
推迟调用的函数其参数会立即求值,但直到外层函数返回前该函数都不会被调用。
以下是一段代码示例:
package main
import "fmt"
func main() {
defer fmt.Println("world")
fmt.Println("hello")
}
输出结果:
hello
world
7.func
func关键字用于定义函数。函数是程序的基本构建块,用于封装可重复使用的代码逻辑,提高代码的可读性、可维护性和复用性。
以下是一段代码示例:
package main
import {
"fmt"
}
func add(a int,b int) int {
return a + b
}
func add2(a,b int) int { //a,b都是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(){
res := add(1,2)
fmt.Println(res) //3
v,ok := exists(map[string]string("a" : "A"),"a")
fmt.Println(v,ok) //A true
}
关于exist函数:
当前代码定义了一个名为 exists 的函数,该函数用于检查给定的键 k 是否存在于给定的映射 m 中。如果键 k 存在于映射 m 中,则函数返回该键对应的值 v 和 true,表示键存在;如果键 k 不存在于映射 m 中,则函数返回空字符串 "" 和 false,表示键不存在。
-
函数接受两个参数:
m是一个映射类型的参数,其键和值都是字符串类型;k是一个字符串类型的参数,表示要查找的键。 -
函数内部使用了一个简短的变量声明
v, ok = m[k],这行代码尝试从映射m中获取键k对应的值,并将获取到的值赋给变量v,同时将一个布尔值ok设置为true表示键存在,或者设置为false表示键不存在。 -
最后,函数使用
return语句返回变量v和ok,即返回键对应的值和一个布尔值,表示键是否存在。
8.指针和结构体
指针:
不同于C的指针,Go没有指针运算。Go的指针保存了值的内存地址。
类型 *T 是指向 T 类型值的指针,其零值为 nil。
var p *int
& 操作符会生成一个指向其操作数的指针。
i := 42
p = &i
* 操作符表示指针指向的底层值。
fmt.Println(*p) // 通过指针 p 读取 i
*p = 21 // 通过指针 p 设置 i
即通常所说的解引用(间接引用)。
结构体:
结构体是Go语言中用于将多个不同类型的数据字段组合在一起的复合数据类型。它类似于其他编程语言中的类或记录(record),但Go语言没有类的概念。结构体主要用于表示具有多个属性的数据实体,如用户、订单、商品等。
基本语法:
type 结构体名称 struct {
字段名1 字段类型1
字段名2 字段类型2
// 更多字段...
}
结构体方法:
结构体方法是与特定结构体类型关联的函数。通过方法,结构体类型可以拥有行为,实现数据和操作的封装。
基本语法:
func (接收者 接收者类型) 方法名(参数列表) (返回值列表) {
// 方法体
}
示例代码如下:
package main
import "fmt"
type user struct {
name string
password string
}
// 定义了一个名为 checkPassword 的方法,该方法属于 user 结构体。
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
}
9.error
在编程中,错误是指程序在执行过程中遇到的异常情况或问题。有效的错误处理机制不仅可以提升程序的健壮性,还能为开发者提供调试和维护的便利。在Go语言中,错误处理的核心在于显式地返回和检查错误值,而非依赖于异常抛出与捕获机制。
在Go语言中,error是一个内置的接口类型,用于表示错误状态。它定义如下:
type error interface {
Error() string
}
Go提供了多种创建错误的方法,比如errors.New,fmt.Errorf......Go中还支持使用自定义错误类型。
10.方法
方法就是一类带特殊的 接收者 参数的函数。
方法接收者在它自己的参数列表内,位于 func 关键字和方法名之间。
例如:
package main
import (
"fmt"
)
type sum struct {
x,y float64
}
func (s sum) Cal() float64 {
return s.x + s.y;
}
func main() {
s := sum{3, 4}
fmt.Println(s.Cal())
}
11.接口
接口(interface)是一种强大的抽象机制,用于定义对象的行为而不关心其具体实现。接口允许不同类型的对象以一致的方式进行交互,从而实现灵活、可扩展和可维护的代码结构。这种抽象机制允许不同类型的对象在满足相同接口的前提下,以一致的方式进行交互,从而实现多态性和代码的高内聚低耦合。
基本语法:
type 接口名称 interface {
方法签名1
方法签名2
// 更多方法签名...
}
Go语言中的接口实现是隐式的,即只要一个类型实现了接口中声明的所有方法,就自动被视为实现了该接口,无需显式声明。
空接口:指定了零个方法的接口值被称为空接口。
类型断言:提供了访问接口值底层具体值的方式。
t := i.(T)
该语句断言接口值 i 保存了具体类型 T,并将其底层类型为 T 的值赋予变量 t。若 i 并未保存 T 类型的值,该语句就会触发一个 panic。
为了判断一个接口值是否保存了一个特定的类型,类型断言可返回两个值:其底层值以及一个报告断言是否成功的布尔值。
t, ok := i.(T)
若 i 保存了一个 T,那么 t 将会是其底层值,而 ok 为 true。否则,ok 将为 false 而 t 将为 T 类型的零值,程序并不会产生 panic。
例子:
package main
import "fmt"
func main() {
var i interface{} = "hello"
s := i.(string)
fmt.Println(s)
s, ok := i.(string)
fmt.Println(s, ok)
f, ok := i.(float64)
fmt.Println(f, ok)
f = i.(float64) // panic
fmt.Println(f)
}
类型选择:类型选择与一般的 switch 语句相似,不过类型选择中的 case 为类型(而非值), 它们针对给定接口值所存储的值的类型进行比较。 即将case处改为值的类型,程序会对值的类型进行判断,进入对应的case。
总结:
Go语言设计简洁,语法直观,易于学习和使用。Go语言结合了高效的性能、简洁的语法和强大的并发支持,使其成为开发现代软件系统,尤其是云服务、分布式系统和网络应用的理想选择。其高效的内存管理和垃圾回收机制确保了应用的高性能和稳定性。