1 Go语言基础语法
1.1 数组
数组是具有编号且长度固定的元素序列。对于数组,可以很方便地取特定索引的值或者往特定索引取存储值,方便打印整个数组。但由于数组的长度固定,因此在真实业务代码里很少直接使用数组。
示例代码:
package main
import "fmt"
func main() {
var a [5]int
a[4] = 100
fmt.Println("get:", a[2])
fmt.Println("len:", len(a))
b := [5]int{1, 2, 3, 4, 5}
fmt.Println(b)
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.2 切片
由于数组长度固定,而切片不同于数组可以任意更改长度,具有更丰富的操作,比如可以用make来创建切片,可以像数组一样去取值,还可以利用append来追加元素,因此在真实业务代码里往往使用切片。
切片特点:
- 使用append追加元素,必须把 append的结果赋值为原数组。
- 在执行append操作时,如果容量不够,会扩容并且返回新的切片。
- 不同于python,切片不支持负数索引。
示例代码:
package main
import "fmt"
func main() {
s := make([]string, 3)
s[0] = "a"
s[1] = "b"
s[2] = "c"
fmt.Println("get:", s[2])
fmt.Println("len:", len(s))
s = append(s, "d")
s = append(s, "e", "f")
fmt.Println(s)
c := make([]string, len(s))
copy(c, s)
fmt.Println(c)
fmt.Println(s[2:5])
fmt.Println(s[:5])
fmt.Println(s[2:])
good := []string{"g", "o", "o", "d"}
fmt.Println(good)
}
1.3 map(哈希/字典)
Go语言中的map与其他编程语言里面的哈希或者字典相同,是实际使用过程中最频繁用到的数据结构。
map的创建与删除:make创建空map会需要两个类型:第一个是key类型,数据结构是string,第二个是value类型,数据结构是int。map创建成功后可以从其中存储或者取出键值对,也可以用delete从map里删除键值对。
map特点:
- golang的map是完全无序的,遍历的时候不会按照字母顺序,也不会按照插入顺序输出,而是随机顺序。
示例代码:
package main
import "fmt"
func main() {
m := make(map[string]int)
m["one"] = 1
m["two"] = 2
fmt.Println(m)
fmt.Println(len(m))
fmt.Println(m["one"])
fmt.Println(m["unknow"])
r, ok := m["unknow"]
fmt.Println(r, ok)
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.4 range遍历
对于切片或者map,可以用range来快速遍历,range遍历的时候,对于数组会返回两个值 第一个是索引,第二个是对应位置的值。如果不需要索引,可以用下划线来忽略。
示例代码:
package main
import "fmt"
func main() {
nums := []int{2, 3, 4}
sum := 0
for i, num := range nums {
sum += num
if num == 2 {
fmt.Println("index:", i, "num:", num)
}
}
fmt.Println(sum)
m := map[string]string{"a": "A", "b": "B"}
for k, v := range m {
fmt.Println(k, v)
}
for k := range m {
fmt.Println("key", k)
}
}
1.5 函数
特点:
- 与其他很多语言不同,变量类型是后置的。
- Golang里面的函数原生支持返回多个值。在实际的业务逻辑代码里面几乎所有的函数都返回两个值,第一个值是真正的返回结果,第二个值是一个错误信息。
示例代码(实现两个变量相加的函数):
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() {
res := add(1, 2)
fmt.Println(res) // 3
v, ok := exists(map[string]string{"a": "A"}, "a")
fmt.Println(v, ok) // A True
}
1.6 结构体
结构体是带类型的字段的集合。实际使用中,可以用结构体的名称去初始化结构体变量,构造的时候需要传入每个字段的初始值,也可以用键值对的方式指定初始值,只对一部分宇字段进行初始化。
示例代码:
package main
import "fmt"
type user struct {
name string
password string
}
func main() {
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}
fmt.Println(checkPassword(a, "haha"))
fmt.Println(checkPassword2(&a, "haha"))
}
func checkPassword(u user, password string) bool {
return u.password == password
}
func checkPassword2(u *user, password string) bool {
return u.password == password
}
1.7 错误处理
在go语言里,往往通过使用一个单独的返回值来传递错误信息完成错误处理。不同于Java处理错误,go语言对错误的处理方式,能够很清晰地知道哪个函数返回了错误,并且能用简单的if else来处理错误。
函数错误处理方式:
- 针对函数,可以在函数的返回值类型里后面加一个error,代表这个函数可能会返回错误。
- 在函数实现的时候,return需要同时return两个值,如果出现错误,那么可以return nil和一个error。如果没有出现错误,那么返回原本的结果和nil。
示例代码:
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", "1024"}}, "wang")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(u.name)
if u, err := findUser([]user{{"wang", "1024"}}, "li"); err != nil {
fmt.Println(err)
return
} else {
fmt.Println(u.name)
}
}
2 Go语言常用特性解析
Go语言是一种新兴的编程语言,由谷歌公司在2009年开发并发布。它具有简单、快速、可靠和可维护等特点,被广泛应用于分布式系统、网络编程、微服务和云计算等领域。下面详细介绍一下Go语言的一些常用特性,并给出对应示例代码。
2.1 并发支持
Go语言支持并发编程,提供了原子操作、通道和锁等相关的API,可以方便地实现并发控制和数据同步。它的并发模型是基于管道和通道实现的,可以有效地避免线程同步的性能问题。
例如,下面是一个使用Go语言实现的简单并发程序,用于打印九九乘法表:
package main
import (
"fmt"
"sync"
)
func printMatrix wg *sync.WaitGroup
wg := &sync.WaitGroup{}
for i := 0; i < 9; i++ {
for j := 0; j < 9; j++ {
fmt.Printf("%d x %d = %d
", i, j, i*j)
wg.Add(1)
}
}
go func() {
wg.Wait()
fmt.Println()
}()
fmt.Println()
)
func main() {
printMatrix(nil)
}
2.2 接口编程
Go语言支持接口编程,可以方便地实现类型之间的组合和聚合。接口定义一个空的方法集合,它不包含任何实现,只是声明了一组方法的名字和参数列表。任何实现了这些方法的类型都可以被看作是该接口的实例。
例如,下面是一个使用Go语言实现的简单接口程序,用于计算两个整数之和:
package main
import "fmt"
type Adder interface {
Add(int, int) int
}
type Sum struct{}
func (s Sum) Add(a, b int) int {
return a + b
}
func main() {
adder := Sum{}
fmt.Println(adder.Add(1, 2))
fmt.Println(adder.Add(3, 4))
}
2.3 泛型编程
Go语言支持泛型编程,可以在定义类型时使用通配符*T来表示任意类型的指针。这种编程方式可以避免硬编码,提高代码的灵活性和可重用性。
例如,下面是一个使用Go语言实现的简单泛型程序,用于实现一个简单的链表:
package main
import "fmt"
type Node struct {
Val interface{}
Next *Node
}
func NewNode(val interface{}) *Node {
return &Node{Val: val, Next: nil}
}
func main() {
head := NewNode(1)
tail := head
for i := 2; i < 10; i++ {
tail.Next = NewNode(i)
tail = tail.Next
}
fmt.Println(head.Val)
fmt.Println(tail.Next.Val)
}
3 总结
本文介绍了Go语言的基础语法,主要包括数组、切片、map、range遍历、函数、结构体和错误处理等具体使用,并针对Go语言并发支持、接口编程和泛型编程等特性进行分析通过真实案例说明上述特性。
本文为个人见解,如有错误欢迎指正!