Go 语言入门指南:基础语法和常用特性解析 | 豆包MarsCode AI刷题

122 阅读6分钟

Why Go?

Go语言,也称为Golang,是由Google开发的一种静态类型、编译型的编程语言。自2009年发布以来,Go因其简洁、高效和强大的特性迅速流行,Go拥有的特点:

    1. 简洁且易于学习

Go语言设计的初衷是简化编程过程。它的语法简单直观,使得新手可以更快地上手,而经验丰富的程序员也能迅速掌握。Go避免了许多现代编程语言中复杂的特性,如类继承和泛型(不用考虑implementation的struct真舒服🤗)提供了一种更直接的编程体验

    1. 高性能

作为编译型语言,Go生成的二进制文件执行速度非常快。其内置的并发支持通过goroutines和channel机制,使得Go在处理并发任务时表现出色,尤其适合网络服务器、分布式系统和大数据处理等领域。

    1. 强大的标准库

Go附带了一个强大的标准库,提供了丰富的功能模块,如网络、加密、I/O操作等。这减少了对第三方库的依赖,使开发者可以更轻松地构建功能齐全的应用程序。

    1. 易于部署

Go编译生成的可执行文件是静态链接的独立文件,不依赖外部库。这大大简化了部署过程,特别是在需要跨平台部署的情况下,Go程序可以在不同操作系统之间轻松移植。

    1. 社区和生态系统

Go拥有一个活跃的社区和不断增长的生态系统。丰富的开源库和工具支持使开发者能够快速找到所需的解决方案和技术支持。此外,Go的包管理工具(如Go Modules)使得依赖管理更加简单和高效。

    1. 企业支持

许多知名科技公司如Google、Uber、Dropbox和Netflix,还有我萌国内知名的ByteDanceB站,都在使用Go语言进行核心业务的开发。这不仅显示了Go的可靠性和性能,也为Go的持续发展提供了强大的推动力。

Go的基础语法

程序结构

Go 程序由包声明导入语句、函数定义等组成,以下是一个简单的Go程序例子:

package main

import(
    "fmt"
)

func main (){
    fmt.Println("Hello Go!")
}

以上介个简单例子我们可以看出来构成Go程序的三要素:包声明、导入、函数,与其他语言不同的一点就是声明函数用的func (),真简洁喵

变量与常量

Go语言使用var keyword进行声明变量,const来进行声明常量,我们可以不指定它的类型,编译器会自动推断的,和Python有点像hhh

var IntegerNum int  //带指定类型的声明,不赋值
var IntegerNum2 int = 15 //不带指定类型的声明,编译器会自动推断
const pi = 3.14 //常量

还有一种短变量声明,是做到了即声明又赋值的操作,作用域只在函数内部:

IntegerNum:= 30

基本数据类型

Go和其他语言一样都支持多种基本数据类型(但没有char噢)

var IntegerNum int = 5 //Integer
var FloatNum float64 = 3.141 // Float64
var isGoExcellent = true // Boolean
var Lang string = "Go"

控制结构

Go和其他语言一样都有着常见的控制结构,比如if啦,for啦,switch这些的,但注意的是for是Go中唯一的循环结构喵

// 和CPP的for语句类似
for i := 0; i < 5; i++ {
    fmt.Println(i)
}

// If结构
if x > 0 {
    fmt.Println("x is positive")
} else {
    fmt.Println("x is not positive")
}

// switch结构,不过与cpp不同的是,Go的switch不用考虑在每个case下break
switch x {
case 1:
    fmt.Println("One")
case 2:
    fmt.Println("Two")
default:
    fmt.Println("Other")
}

要做到像cpp那样的 while(),可以直接用for()

for{
    ...
}

指针

Go用到的指针真的比CPP方便理解多了,神降Go拯救我

func increse (num *int){
    *num++
}
...
increse(&num) //<--像cpp那样用&表示变量的地址

数组和切片(Slice)

在Go中,数组是固定长度的,而切片是动态的,可扩容的,比如:

var arr [3]int = [3]int{1, 2, 3}
slice := []int{4, 5, 6}
slice = append(slice, 7)

fmt.Println(arr)   // 输出: [1 2 3]
fmt.Println(slice) // 输出: [4 5 6 7]

上述例子可以看出...Slice的扩容要用 .append(sliceName, value)

Map

Go的map内部使用hash实现的,反正也是众多语言中常见的结构了= = 看个简单的例子就知道惹

ages := map[string]int{
    "Alice": 25,
    "Bob":   30,
}

ages["Charlie"] = 35
fmt.Println(ages["Alice"]) // 25

Go特性

除了基础语法外,Go语言还有许多强大且实用的特性,使其在开发过程中高效且灵活。

并发

  • Goroutine

Go语言直接就内置了对并发的支持,通过goroutine实现轻量级的线程(协程),创建goroutine直接使用go func()就行了,简洁不拖泥带水

func say(s string) {
    for i := 0; i < 5; i++ {
        fmt.Println(s)
    }
}

func main() {
    go say("Hello")
    go say("World")

    time.Sleep(time.Second)
}
  • Channel

在Go中,channel用于在goroutine中间的通信,可以确保同步和数据安全

func sum(s []int, c chan int) {
    sum := 0
    for _, v := range s {
        sum += v
    }
    c <- sum // 将结果发送到channel
}

func main() {
    s := []int{7, 2, 8, -9, 4, 0}

    c := make(chan int)
    go sum(s[:len(s)/2], c)
    go sum(s[len(s)/2:], c)
    x, y := <-c, <-c // 从channel接收数据

    fmt.Println(x, y, x+y)
}

不过需要注意的是channel是可以设置缓冲区的,当channel有缓冲区时goroutine之间就不是同步的效果了,不会发生阻塞,当缓冲区为0或传输的数据大于缓冲区值时才会发生

接口

在Go中使用接口来实现多态,可以通过定义行为而非implementation来提高代码的灵活性,掏出我萌的猫猫狗狗朋友:

type Animal interface {
    Speak() string
}

type Dog struct{}
func (d Dog) Speak() string {
    return "Woof!"
}

type Cat struct{}
func (c Cat) Speak() string {
    return "Meow!"
}

func main() {
    var a Animal
    a = Dog{}
    fmt.Println(a.Speak()) // 输出: Woof!

    a = Cat{}
    fmt.Println(a.Speak()) // 输出: Meow!
}

错误处理

Go使用显式的错误处理机制,通过返回错误值进行判断,而不是异常机制,不像java或者py那样直接就把error抛出去了,比如:

func divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, fmt.Errorf("division by zero")
    }
    return a / b, nil
}

func main() {
    result, err := divide(10, 0)
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println("Result:", result)
    }
}

Defer

defer用于延迟函数的执行,通常用于资源清理,如关闭文件、释放锁等:

func main() {
    file, err := os.Open("file.txt")
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close() // 确保在函数结束时关闭文件

    // 对文件进行操作
}

Range

在Go中range用于迭代slicemaparraystringchannel(没错,channel也是能遍历的)

nums := []int{2, 3, 4}
sum := 0
for _, num := range nums {
    sum += num
}
fmt.Println("sum:", sum)

kvs := map[string]string{"a": "apple", "b": "banana"}
for k, v := range kvs {
    fmt.Printf("%s -> %s\n", k, v)
}

这些特性使Go语言在开发过程中更加灵活和高效,特别是在处理并发、接口设计和资源管理等方面,真的是太方便了!!