Go 语言入门指南:基础语法和常用特性|青训营

230 阅读7分钟

GoLang语言入门

简介

GoLang(也被称为Go)是一门由Google开发的开源编程语言。它在许多方面都非常优秀,具有以下特点:

  1. 高性能、高并发:Go语言通过轻量级的线程(goroutine)和通信原语(channel)实现高效的并发编程,适合构建高性能的分布式系统。
  2. 语法简单、学习曲线平缓:Go的语法设计简洁,易于理解,没有繁琐的特性和复杂的用法,初学者可以快速上手。
  3. 丰富的标准库:Go拥有一个强大的标准库,涵盖了网络、文件处理、加密、文本处理等多个领域,开发者可以直接使用这些库来提高开发效率。
  4. 完善的工具链:Go提供了一套全面的工具,包括格式化工具、测试工具、性能分析工具等,方便开发者进行代码管理和优化。
  5. 静态链接:Go语言的编译器将所有依赖打包为一个可执行文件,简化了部署和交付过程。
  6. 快速编译:Go的编译速度很快,对于大型项目也能快速完成编译,提高了开发效率。
  7. 跨平台:Go可以在各种操作系统上运行,开发者可以在不同平台上编译和运行相同的代码。
  8. 垃圾回收:Go拥有自动内存管理,内置垃圾回收机制,开发者不需要手动管理内存,减少了出现内存泄漏的可能性。

基础语法

HelloWorld

package main

import "fmt"

func main() {
	fmt.Println("HelloWorld!")
}

定义变量

Go语言中的基本数据类型包括:

  • 布尔类型:bool
  • 字符串类型:string
  • 整数类型:int, int8, int16, int32, int64
  • 无符号整数类型:uint, uint8, uint16, uint32, uint64, uintptr
  • 字节类型:byte(uint8的别名)
  • Unicode字符类型:rune(int32的别名)
  • 浮点数类型:float32, float64
  • 复数类型:complex64, complex128
package main

import "fmt"

func main() {
	var a = 100 // 使用var关键字声明变量,编译器自动推断类型
	fmt.Println("a =", a)

	c := 'A' // 使用:=短变量声明,编译器自动推断类型
	fmt.Println("c =", c)

	var b float64 = 64.648 // 显式声明变量类型
	fmt.Println("b =", b)

	const name = "stacker" // 常量声明
	fmt.Println("name =", name)
}

if - else流程控制语句

package main

import (
	"fmt"
	"math"
)

func pow(x, n, lim float64) float64 {
	if v := math.Pow(x, n); v < lim {
		return v
	} else {
		fmt.Printf("%g >= %g\n", v, lim)
	}
	// 这里开始就不能使用 v 了
	return lim
}

func main() {
	fmt.Println(
		pow(3, 2, 10),
		pow(3, 3, 20),
	)
}

for循环

在Go语言中,for循环可以用于多种情况。

  1. 类似C语言中的for循环:
package main

import "fmt"

func main() {
	sum := 0
	for i := 0; i < 10; i++ {
		sum += i
	}
	fmt.Println(sum)
}
  1. 类似C语言中的while循环:
package main

import "fmt"

func main() {
	sum := 1
	for sum < 1000 {
		sum += sum
	}
	fmt.Println(sum)
}
  1. 无限循环(类似C语言中的While(1)):
package main

func main() {
	for {
		// 循环体
	}
}

switch分支结构

Go语言的switch语句与C、Java等语言有所不同。Go的switch默认是带有break的,即匹配到一个分支后会自动跳出switch,不会继续执行其他分支。如果需要贯穿多个分支,可以使用fallthrough关键字实现。

package main

import (
	"fmt"
	"runtime"
)

func main() {
	fmt.Print("Go runs on ")
	switch os := runtime.GOOS; os {
	case "darwin":
		fmt.Println("OS X.")
	case "linux":
		fmt.Println("Linux.")
	default:
		fmt.Printf("%s.\n", os)
	}
}

数组

package main

import "fmt"

func main() {
	var a [2]string
	a[0] = "Hello"
	a[1] = "World"
	fmt.Println(a[0], a[1])
	fmt.Println(a)

	primes := [6]int{2, 3, 5, 7, 11, 13}
	fmt.Println(primes)
}

切片*

切片是Go中重要的数据结构,可以看作是数组的一种引用。切片提供了对数组的动态访问,更加灵活和方便。

package main

import "fmt"

func main() {
	primes := [6]int{2, 3, 5, 7, 11, 13}

	var s []int = primes[1:4]
	fmt.Println(s)
}

使用make函数创建切片:

package main

import "fmt"

func main() {
	a := make([]int, 5)
	printSlice("a", a)

	b := make([]int, 0, 5)
	printSlice("b", b)

	c := b[:2]
	printSlice("c", c)

	d := c[2:5]
	printSlice("d", d)
}

func printSlice(s string, x []int) {
	fmt.Printf("%s len=%d cap=%d %v\n",
		s, len(x), cap(x), x)
}

使用append函数向切片追加元素:

package main

import "fmt"

func main() {
	var s []int
	printSlice(s)

	// 添加一个空切片
	s = append(s, 0)
	printSlice(s)

	// 这个切片会按需增长
	s = append(s, 1)
	printSlice(s)

	// 可以一次性添加多个元素
	s = append(s, 2, 3, 4)
	printSlice(s)
}

func printSlice(s []int) {
	fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}

map

map是Go语言中的一种关联数据类型,也称为字典或哈希表。它由一系列键值对组成,每个键值对表示一个映射关系。

package main

import "fmt"

type Vertex struct {
	Lat, Long float64
}

var m map[string]Vertex

func main() {
	m = make(map[string]Vertex)
	m["Bell Labs"] = Vertex{
		40.68433, -74.39967,
	}
	fmt.Println(m["Bell Labs"])
}

range

range用于遍历数组、切片、字符串、map等数据结构。它返回索引和元素的值。

package main

import "fmt"

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}

func main() {
	for i, v := range pow {
		fmt.Printf("2**%d = %d\n", i, v)
	}
}
package main

import "fmt"

func main() {
	pow := make([]int, 10)
	for i := range pow {
		pow[i] = 1 << uint(i) // == 2**i
	}
	for _, value := range pow {
		fmt.Printf("%d\n", value)
	}
}

函数

函数是Go中的基本组件之一,可以在函数中执行特定的任务并返回结果。Go语言支持多参数、多返回值和命名返回值。

package main

import "fmt"

func add(x int, y int) int {
	return x + y
}

func main() {
	fmt.Println(add(42, 13))
}

简化后的参数声明:

package main

import "fmt"

func add(x, y int) int {
	return x + y
}

func main() {
	fmt.Println(add(42, 13))
}

支持多返回值:

package main

import "fmt"

func swap(x, y string) (string, string) {
	return y, x
}

func main() {
	a, b := swap("hello", "world")
	fmt.Println(a, b)
}

返回值可命名:

package main

import "fmt"

func split(sum int) (x, y int) {
	x = sum * 4 / 9
	y = sum - x
	return
}

func main() {
	fmt.Println(split(17))
}

指针

指针是一种特殊的数据类型,用于存储变量的内存地址。通过指针,可以直接访问变量的内存内容。

package main

import "fmt"

func main() {
	i, j := 42, 2701

	p := &i         // 指向 i
	fmt.Println(*p) // 通过指针读取 i 的值
	*p = 21         // 通过指针设置 i 的值
	fmt.Println(i)  // 查看 i 的值

	p = &j         // 指向 j
	*p = *p / 37   // 通过指针对 j 进行除法运算
	fmt.Println(j) // 查看 j 的值
}

结构体

结构体是一种复合数据类型,可以用来表示一组相关字段的集合。

package main

import "fmt"

type Vertex struct {
	X int
	Y int
}

func main() {
	fmt.Println(Vertex{1, 2})
}

结构体方法

在Go语言中,结构体可以定义方法,方法是一种特殊的函数,与结构体关联。

package main

import "fmt"

type User struct {
	Username string
	Password string
}

// 普通方法
func resetPassword(u User, password string) {
	u.Password = password
}

// 结构体方法
func (u *User) resetPassword(password string) {
	u.Password = password
}

func main() {
	user := User{
		Username: "john",
		Password: "123456",
	}

	// 调用普通方法
	resetPassword(user, "new_password")
	fmt.Println("普通方法修改后的密码:", user.Password)

	// 调用结构体方法
	user.resetPassword("new_password2")
	fmt.Println("结构体方法修改后的密码:", user.Password)
}

错误处理

在Go中,错误是一种普遍的返回值类型,通常用于表示函数调用过程中发生的错误。可以使用errors.New()函数创建一个新的错误实例。

package main

import (
	"errors"
	"fmt"
)

func Hello(name string) (string, error) {
	if name == "" {
		return "", errors.New("empty name error!")
	}
	message := fmt.Sprintf("Hi, Hello %s", name)
	return message, nil
}

字符串操作

Go语言提供了丰富的字符串操作函数,可以方便地进行字符串处理。

package main

import (
	"fmt"
	"strings"
)

func main() {
	var str string = "golang golang"

	// 字符串克隆
	var tmpStr string = strings.Clone(str)
	fmt.Println("str =", str, " tmpStr =", tmpStr)

	// 字符串比较
	if strings.Compare(str, tmpStr) == 0 {
		fmt.Println("same!")
	} else if strings.Compare(str, tmpStr) == 1 {
		fmt.Println("str bigger")
	} else { // strings.Compare(str, tmpStr) == -1
		fmt.Println("str smaller")
	}

	// 字符串包含
	if strings.Contains(str, "go") {
		fmt.Println(str, " has go")
	}

	// 字符串计数
	var counter int = strings.Count(str, "go")
	fmt.Println("counter =", counter)

	// 字符串索引 不存在返回-1
	var index int = strings.Index(str, " ")
	fmt.Println("index =", index)
}

JSON处理

Go语言内置了对JSON的支持,可以方便地进行JSON的序列化和反序列化。

package main

import (
	"fmt"
	"encoding/json"
)

type UserInfo struct {
	Name string
	Age  int
}

func main() {
	user := UserInfo{Name: "stackor", Age: 18}

	// 序列化为JSON格式
	buf, err := json.Marshal(user)
	if err != nil {
		panic(err)
	}
	fmt.Println(buf)       // 输出二进制数据
	fmt.Println(string(buf)) // 输出JSON字符串

	// 反序列化JSON数据
	var b UserInfo
	err = json.Unmarshal(buf, &b)
	if err != nil {
		panic(err)
	}
	fmt.Printf("%#v", b)
}

时间处理

Go语言提供了时间相关的函数和结构体,可以方便地进行时间的表示和计算。

package main

import (
	"fmt"
	"time"
)

func main() {
	nowTime := time.Now()
	fmt.Println(nowTime) // 例如:2023-07-25 11:29:13.985157 +0800 CST m=+0.000144293

	t := time.Date(2003, 11, 21, 2, 30, 30, 0, time.UTC)
	fmt.Println(t)
	fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second())
	fmt.Println(t.Format("2006-01-02 03:04:05"))

	t2 := time.Date(2003, 11, 22, 3, 30, 30, 0, time.UTC)
	diff := t2.Sub(t)
	fmt.Println(diff) // 输出:25h0m0s

	// 获取时间戳
	fmt.Println(nowTime.Unix())
}

数字转换

在Go语言中,可以通过strconv包进行字符串和基本数据类型之间的转换。

package main

import (
	"fmt"
	"strconv"
)

func main() {
	f, _ := strconv.ParseInt("100", 10, 64)
	fmt.Println(f)

	f, _ = strconv.ParseInt("0x1000", 0, 64)
	fmt.Println(f)

	t, _ := strconv.ParseFloat("12.1012", 64)
	fmt.Println(t)

	n1, _ := strconv.Atoi("123")
	fmt.Println(n1)

	n2, err := strconv.Atoi("AAA")
	fmt.Println(n2, err)
}