Go基本语法

Go基本语法

易错语法

  1. 无分号
  2. 定义了的变量一定要用
  3. 注意for循环不能加括号()
  4. else 语句应该与 if 语句在同一行,或者在 if 语句的右大括号之后。
  5. string不可修改
  6. 全局变量只能显式定义(必须写明类型)

变量

显式类型,定义了而未使用会报错

// 单行(有时候type可以自动推导出来)
var name type

// 多变量
var(
    name1 type1
    name2 type2
)

// 未定义变量可以用 := 自动推导
name := "ct"

// 变量交换
b, a = a, b

// 匿名变量:可抛弃,可以重复用
_ := test()

// 常量
const NAME type

// iota:const出现时被重置位0,出现一个常量就++
const (
    a = iota //0
    b //1
    c //2
    d = "111" // "111"  iota 3
    e // "111" iota 4
    f = 100 //iota 5
    g //100 iota 6
    h = iota //iota 7
    i //iota 8
)

const(
    j = iota //0
    k //1
)

IO

fmt.Scanf()
fmt.Scan()
fmt.Scanln()

fmt.Printf()
fmt.Print()
fmt.Println()

switch

// fallthrough:直接穿透下一个case。无视当前结果,强制执行后面的var tt int =  10
	switch tt {
	case 9:
		fmt.Printf("case9: tt=%d\n", tt)
		fallthrough
	case 10:
		fmt.Printf("case10: tt=%d\n", tt)
		fallthrough //fallthrough: continue run next case
	case 8:
		fmt.Printf("case8: tt=%d\n", tt)
	case 7:
		fmt.Printf("case7: tt=%d\n", tt)
	case 5:
		if (a == 10) {
			break;
		}
		fmt.Printf("case5: tt=%d\n", tt)
	}

for

注意for循环不能加括号()

	for i := 1; i <= 10; i++ {
		fmt.Printf("i=%d ", i)
	}

	//for range
	str := "TT fish"
	for i, v := range str { //i下标,v对应值
		fmt.Printf("%d: %c\n", i, v)
	}

函数

基础函数

	// func 名字 (参数) (返回类型)
	//func name(par1 type1, par2 type2...) (return_type_1, return_type_2)
	func cal(a int, b int, s string) (int, int, string) {
		return a + b, a * b, s
	}

	//main里面:
	x, y, s := cal(2, 3, "tt")
	
	//可变参数(传入数量待定),如果还有固定参数的混合用的话,可变参数要放在最后,且只有一个可变参数
	func calsum(a ...int) (...) {}

匿名函数

只用一次没有名字

	//匿名函数
	func() {
		fmt.Printf("anonymous\n")
	}()
	
	a, b := func(a int, b int) (int, int) {
		fmt.Printf("infunc: a + b = %d\n", a + b)
		return a, b
	}(4, 5)
	fmt.Printf("outfunc: a = %d, b = %d\n", a, b)

高阶函数(回调函数)

把函数作为参数,这样同类型的函数就可以直接复合传参使用了

	func add (a int, b int) (int) {
		return a + b
	}
	//其它函数略,总之保持类型一样就好
	func operator(a int, b int, f func(int, int)(int)) int {
		return f(a, b)
	}

	//main里面:
	a := 9
	b := 3
	fmt.Printf("add: %d\n", operator(a, b, add))
	fmt.Printf("del: %d\n", operator(a, b, del))
	fmt.Printf("mul: %d\n", operator(a, b, mul))
	fmt.Printf("div: %d\n", operator(a, b, div))

闭包

有点绕
闭包:函数套函数,内层修改了外层函数的局部变量,且外层函数返回值是内层函数,则构成闭包
局部变量生命周期:正常的局部变量会随着函数的结束而销毁,而闭包的外层函数的局部变量不会随着外层函数的结束而销毁,因为内层函数仍在使用

//闭包
func inc() (func() int) {
	i := 0
	f := func() int {
		i++
		return i
	}
	return f
}

func main() {
	r1 := inc()
	fmt.Println(r1)
	v1 := r1()
	fmt.Printf("%d ", v1)
	v2 := r1()
	fmt.Printf("%d ", v2)
	fmt.Printf("%d ", r1())
	fmt.Printf("%d ", r1())
	fmt.Printf("%d\n", r1())
	fmt.Println("----------")
	r2 := inc() //重新调用
	v3 := r2()
	fmt.Printf("%d ", v3)
	fmt.Printf("%d ", r1()) //r1仍不变
	fmt.Printf("%d\n", r2()) 
}

/*输出:
0xee9f60
1 2 3 4 5
----------
1 6 2
*/

数组 切片

值传递:array,单变量
引用传递:slice,map,chan

	//数组定义
	arr := [4] int {1, 2, 3, 4} //大小固定

	//切片定义
	arr2 := [] int {1, 2, 3, 4} //大小可变

异常

defer

用法:通常是打开一个资源或者文件之后立马defer,以便及时释放

	//defer之后的会被延迟到最后执行,且函数执行到最后时,defer语句按栈顺序执行
	//defer之后跟函数,则参数已被传入,只是最后再执行
	fmt.Printf("0 ")
	defer fmt.Printf("3 ")
	defer fmt.Printf("4 ")
	fmt.Printf("1 ")
	defer fmt.Printf("5 ")
	fmt.Printf("2 ")
	//输出: 0 1 2 5 4 3

异常处理

defer + recover 捕获和处理异常

func testErr() {
	defer func() {
		err := recover()
		if (err != nil) {
			fmt.Println("err = ", err)
		}
	}()
	a := 10
	b := 0
	t := a / b //这个以后的都不会正常执行,直接跳转到defer,之后返回
	fmt.Printf("ans = %d\n", t)
	fmt.Printf("tt\n")
}

	//main里面...
	testErr()
	fmt.Printf("tt2\n") //这个可以正常执行

自定义错误

	errors.New("...")

并发 goroutine

sync

并发执行,无需通信

import (
	"fmt"
	"sync"
	"time"
)

var wg sync.WaitGroup

func download(url string) {
	fmt.Println("start to download", url)
	time.Sleep(time.Second) // 模拟耗时操作
	wg.Done() //计数--
}

func main() {
	for i := 0; i < 3; i++ {
		wg.Add(1) //计数+1
		go download("a.com/" + string(i+'0')) //go 关键字用于启动一个新的 goroutine
	}
	wg.Wait() //等待所有的协程执行结束。
	fmt.Println("Done!")
}

channel

可以在协程之间传递消息。阻塞等待并发协程返回消息。
(所以大概是一个进程执行完之后才会进行下一个吗有点疑惑O.O

var ch = make(chan string, 10) // 创建大小为 10 的缓冲信道

func download(url string) {
	fmt.Println("start to download", url)
	time.Sleep(time.Second)
	ch <- url // 将 url 发送给信道
}

func main() {
	for i := 0; i < 3; i++ {
		go download("a.com/" + string(i+'0'))
	}
	for i := 0; i < 3; i++ {
		msg := <-ch // 等待信道返回消息。
		fmt.Println("finish", msg)
	}
	fmt.Println("Done!")
}

单元测试

牛啊直接测名字后面加上_test就行
感觉这个功能很方便写题(赞美

// main_test.go
package main

import "testing"

func TestAdd(t *testing.T) {
    if ans := add(1, 2); ans != 3 {
        t.Error("add(1, 2) should be equal to 3")
    } else {
        t.Log("Test 1 passed")
    }
    if ans := add(2, 2); ans != 4 {
        t.Error("add(2, 2) should be equal to 4")
    } else {
        t.Log("Test 2 passed")
    }
}

包和模块

这块折磨了很久(感觉自己很笨😭
详见这篇Bug解决:https://www.cnblogs.com/CTing/p/18716582
和原理:https://geektutu.com/post/quick-golang.html#9-包-Package-和模块-Modules

posted @   Sakana~  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示