Go语言入门指南 | 豆包MarsCode AI刷题

75 阅读9分钟

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 函数接受三个参数:

  1. 类型:切片的元素类型。
  2. 长度:切片的初始长度。
  3. 容量(可选):切片的初始容量。如果省略,容量将与长度相同。

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 中,则函数返回该键对应的值 vtrue,表示键存在;如果键 k 不存在于映射 m 中,则函数返回空字符串 ""false,表示键不存在。

  1. 函数接受两个参数:m 是一个映射类型的参数,其键和值都是字符串类型;k 是一个字符串类型的参数,表示要查找的键。

  2. 函数内部使用了一个简短的变量声明 v, ok = m[k],这行代码尝试从映射 m 中获取键 k 对应的值,并将获取到的值赋给变量 v,同时将一个布尔值 ok 设置为 true 表示键存在,或者设置为 false 表示键不存在。

  3. 最后,函数使用 return 语句返回变量 vok,即返回键对应的值和一个布尔值,表示键是否存在。

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语言结合了高效的性能、简洁的语法和强大的并发支持,使其成为开发现代软件系统,尤其是云服务、分布式系统和网络应用的理想选择。其高效的内存管理和垃圾回收机制确保了应用的高性能和稳定性。