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

113 阅读7分钟

1. 什么是Go语言

Go语言是由Google开发的一种开源的静态编程语言,于2009年正式推出。Go语言具有简洁、高效、并发性强等特点,在开发高性能的分布式系统和并行程序领域的效率要优于大多数编程语言。

2. Go语言的基础语法

2.1 "hello wold"

在Go语言中,经典案例"hello world"的代码如下所示:

package main  
  
import "fmt"  
  
func main() {
    fmt.Println("hello world")  
}

Go语言使用package指明当前文件所属的包,同一目录下的文件属于同一个包,package main代表"hello world"的代码文件属于main包。请注意,main包在Go语言中为程序的入口包,每个可执行的程序都应当含有main包作为程序入口。

在Go语言中,我们可以通过import导入包。案例中的import "fmt代表我们导入了fmt包。fmt包为Go语言标准库中提供的包,用于格式化文本并输入或输出。除了Go语言标准库中的包,我们也可以创建自己的包并导入。当我们需要导入多个包时,我们可以通过括号用一个import关键字一次性导入多个包:

import (
    "fmt"
    "math"
    "myOwnPackage"//导入自定义包
)

func main() {...}是我们程序的主函数,是程序执行的起点。Println()则是我们从fmt包中调用的函数,用于输出"hello world"。其执行结果如下: QQ截图20230731205418.png

2.2 变量

Go语言中的变量可以通过var关键字声明,在声明变量时,我们无需显式地指定变量的类型,而是可以让Go语言根据初始化的变量值自行推导对应类型。当然,如果有必要,我们也可以指明变量类型,但需要注意的是,Go语言中的变量类型是后置的。对于没有初始化赋值的变量,我们则必须声明其类型。

var a = 12
var b string = "name"
var c float32

另一种声明变量的方式是使用:=声明变量。通过这种方式声明变量同样无需指明变量类型,但这种方式只能在函数内使用。

y := 12

2.3 常量

常量在Go语言中通过const关键字声明且必须在声明时赋值,常量的值不可更改。Go语言中常量的一大特点在于其没有确定的类型,而是由Go语言根据使用常量的相关代码自行推断类型,这极大的便利了常量在程序中的使用。

const n = 0.99

2.4 for循环

for循环是Go语中的唯一循环语句,其使用方式与Java中相似,但在Go语言中无需通过括号包裹条件语句,实例如下所示:

for i := 0; i < 10; i++ {  
    fmt.Println(i)  
}

我们可以通过breakcontinue随时终断循环或继续循环。

for i := 0; i < 10; i++ {  
    if i == 8 {  
       break  
    }  
    if i%2 == 0 {  
       fmt.Println(i)  
    } else {  
       continue  
    }
}

在这里,我们引出Go语言中的if-else语句。

2.5 if-else语句

Go语言中if-else语句的使用与Java中大体一致,其条件语句同样无需括号包裹,示例如下:

if i != 5 {
   i = i + 1 
} else {
    i = i * 2
}

2.6 switch

switch在Go语言中的运用与在C和C++中类似,switch后的变量名同样无需括号,并且在Go语言中可以不在switch后加变量而是在case后见条件语句,其示例如下:

switch a {
case 1:
    fmt.Println("first")
case 2:
    fmt.Println("second")
case 3:
    fmt.Println("third")
default:
    fmt.Println("other")
}

i := 2
j := 3
switch {
case i < j:
    fmt.Println(i)
default:
    fmt.Println(j)
}

2.7 数组

除了变量类型后置外,数组在Go语言中的使用与Java相似,示例如下:

var a [5]int
b := [5]int{1, 2, 3, 4, 5}
a[1] = 10
length := len(a)
fmt.Println(a[1], length, b)

值得注意的是,在真实的业务中我们较少使用数组。因为数组长度固定,在业务场景下不如切片灵活。

2.8 切片

切片不同于数组,可以任意更改长度,操作也更加丰富,我们同样可以使用len()函数获取切片长度和像数组一样去取值,我们还可以通过append()函数追加元素。

go := make([]string, 2) 
go[0] = "g" 
go[1] = "o" 
fmt.Println(s[2], len(s))
go = append(s, "o") 
go = append(s, "d") 
fmt.Println(go) //[g o o d]

2.9 Map

Go语言中的Map是一组无序的键值对,与Java中类似,但值得注意的是,golang中的Map遍历时不按照插入顺序或字母顺序,而是完全无序。

m := make(map[string]int)
m["one"] = 1
m["two"] = 2
fmt.Println(m) // map[one:1 two:2]    

2.10 range遍历

在Go语言中,无论是Map还是切片,我们都可以通过range快速遍历。注意:range在遍历数组时会返回两个值,一个是索引,一个是索引位置的值。

// 对于数组 num
for i, num := range nums { 
    sum += num 
    if num == 1 { 
       fmt.Println("index:", i, "num:", num) 
    }
}

// 对于Map m
for k, v := range m { 
    fmt.Println(k, v)
}

2.11 指针

Go语言中的指针主要的作用是对传入参数进行修改。在不使用指针的情况下,函数内对于参数的修改实际是对于拷贝的修改,外部的参数是不会变化的。我们需要通过*&符号匹配指针参数类型。

func add(n int) {
    n += 5
}

func addptr(n *int) {
    *n += 5
}

func main() {
    n := 10
    add(n)
    fmt.Println(n) // 10
    addptr(&n)
    fmt.Println(n) // 15
}

2.12 结构体

Go语言中的结构体是带类型的字段的集合,可以封装多个字段构造复杂数据结构。下面的示例代码中,我们改造了一个用户结构体,封装了四个字段,用户名、ID、邮箱和密码。

type user struct { 
  username string 
  id int
  email string
  password string 
}

2.13 Go语言中的函数返回值

Go语言中的函数通过func关键字定义,与Java不同的是,Go语言中的函数可以返回任意数量的值,示例如下:

func cube(x, y int) (int, int) {
    return x * x * x, y * y * y
}

3. 常用特性

3.1 错误处理

因为Go语言中可以返回多个值,所以在Go语言中我们使用单独的错误值来返回错误信息。在Go语言中,除了常规的函数返回值外,我们还会添加一个特殊的返回值error,在出现错误时,返回nil和error,如果一切正常,则正常返回nil和结果。与Java中的异常相比,Go语言中的处理方式可以帮助开发者更清晰的辨认出现错误的函数,仅仅是通过条件判断语句(if-else)就可以处理错误,其示例如下:

package main 
import ( 
  "errors" 
  "fmt" 
)

func div(a, b int) (int, error) { 
     if b == 0 { 
        return nil, errors.New("divided by zero") 
     } 
     return a / b, nil 
}

func main() {
     result, err := div(12, 4)
     if err != nil {
        fmt.Prrintln(err)
        return
     }
     fmt.Println(result) // 3
     
     if result, err := div(5, 0); err != nil {
        fmt.Prrintln(err) // divided by zero
        return
     } else {
         fmt.Println(result)
     }
}

3.2 并发编程

在Go语言中配置了轻量级的线程goroutine和通道channel,方便使用者编写并发程序。我们可以通过使用go关键字启动新的线程并通过channel实现线程间的数据交换。示例如下:

func main() {
    ch := make(chan int)

    go div(12, 4, ch)
    go div(12, 3, ch)

    x := <-ch
    y := <-ch
    fmt.Println(x + y) // 7
}

func div(x, y int, ch chan int) {
    time.Sleep(time.Second)
    ch <- x / y
}

总结

本篇文章仅仅是对于Go语言基础语法和常用特性的初级解析,希望能帮助各位初学者掌握Go语言基础知识,尽快踏上Go语言开发之路。对于Go语言的深入学习,请各位读者根据官方教程学习,鉴于笔者本身也是初学者,文章如有错误之处,欢迎大家指出。