January 12, 2025About 4 min
基本语法
package main
import "fmt"
func main() {
fmt.Println("Hello 世界!")
}
- package:当前go文件属于哪个包,main包通常作为启动包,非启动包最好不好与之重名
- import:顾名思义就是导包的
- func:定义一个函数,通过
.函数名调用方法
包
格式
package "包名"
给包起别名:`import 别名 "包名"
导包
- 第一种,导一个包
import "包名"
- 第二种,导多个包
import (
"包名1"
"包名2"
...
)
- 只导入不调用,只是为了包内的init函数
import _ "math"
// 前面价格斜杠:表示匿名导入
导出或不导出
// 将首字母大写就是导出,外部能访问
// 小写就不能访问
// 变量和包都通用
func sy(){
}
标识符
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
声明常量
批量声明
// 单个声明也行
const (
Count = 1
)
iota
一个内置的常量标识符,常用表示序数,如果声明的常量有序就用这个
简单来说,就是以一种规律对后续的值进行赋值,影响范围到后一个iota
对于每个位置来说都有一个iota对应的就是他的位置号从0开始,
const (
Num = iota // 0
Num1 // 1
Num2 // 2
Num3 = iota * 2 // 3 * 2 = 6会应用下面去,直到新的赋值
Num4 // 4 * 2
)
声明变量
go的类型声明是后置的,有点像ts的类型推断
格式:var 变量名 类型名
// 可以一次定义多个
var a1, a2, a3 int
// 也可以用()
var(
a1 int
a2 int
a3 int
)
// 定义的变量都有一个默认值零值
// 对其进行赋值
var a int = 1
语法糖
var a int = 1 ====> a := 1
// 由编译器去推断类型
name, age := 1, "1"
// 也可以批量去初始化
匿名
就是使用
_
去占位
file, _ := os.Open("readme.txt")
// 有两个参数的但我只需要第一个就这样占位就行
交换
是先计算再进行赋值,完美符合交换
// 可以进行多个交换
a1, a2, a3 := 1, 3, 2
a2, a1, a3 = a3, a2, a1 // 2, 3, 1
====> a2, a1, a3 = 2, 3, 1// 是计算好了再去赋值的
输入输出
os包
有三个暴露的文件描述符
var (
Stdin = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
Stderr = NewFile(uintptr(syscall.Stderr), "/dev/stderr")
)
// 直接使用os.Stdout中的
fmt
里面有实现c类似的printf
- 输出:
fmt.Printf("%d", 1)
- 输出:
fmt.Scan(&a, &b)
使用包装进行加速读取
bufio
func main() { // 配置标准输入流 reader := bufio.NewReader(os.Stdin) var a, b int // 指定流进行读取 fmt.Fscanln(reader, &a, &b) fmt.Printf("%d + %d = %d\n", a, b, a+b) }
scanner
func main() { scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { line := scanner.Text() if line == "exit" { break } fmt.Println("scan", line) } }
条件控制
if
不用(),还可以使用简单语句
if x := 1; x > 1{
// 使用;隔开语句,貌似只能一个表达式
}
label
A:// 一个标记,可以被用来goto或break或continue
// 显然一般适用于多重循环的时候
a:= 1
循环控制
for
格式
for init statement; expression; post statement {
execute statement
}
当只保留条件时就是while
for range
格式
for index, value := range iterable {
// body
}
- index:索引
- value:值
- iterable:可迭代的结构
切片
普通的数组必须给定容量
而切片不需要
初始化
var nums []int // 值
nums := []int{1, 2, 3} // 值
nums := make([]int, 0, 0) // 值
nums := new([]int) // 指针
// 这些方法都可以
- make:三个参数,类型,长度(当前里面有多少个元素),容量
哈希表
map
初始化:mp := map[int]string{ 0: "a" }
- int:这个位置表示键的类型
- string:这个位置表示值的类型
访问:mp[0]
使用键访问
存值:mp[0] = "2"
删除一个键:delete(mp, 0)
给定一个map和一个键
清空:clear(mp)
指针
和c类似
函数
定义
func 函数名([参数列表]) [返回值] {
函数体
}
返回值
func sum(a int, b int) int {}
可以返回多个参数,2个及以上要加括号,返回值使用
,
隔开,有类型具名返回
func sum(a int, b int) (sum int){return}
- 具名的变量名不能与参数中的重复,这里面也是相当于被定义了
- 可以不用return后加东西
- 如果加了,就以return后的为准
延迟计算
- defer:在前面添加一个defer关键词,该函数就会推迟执行
结构体
声明
type Person struct{
name string
age, height int
}
实例化
student := Person{
name: "jack"
age: 20
height: 150
}
方法
声明
type IntSlice []int
// i就是声明的本体,后面是类型
// i相当于this,也就是调用方法的那个上下文
func (i IntSlice) Get(index int) int {
return i[index]
}
func (i IntSlice) Set(index, val int) {
i[index] = val
}
func (i IntSlice) Len() int {
return len(i)
}
eg:
func main() {
var intSlice IntSlice
intSlice = []int{1, 2, 3, 4, 5}
fmt.Println(intSlice.Get(0))
intSlice.Set(0, 2)
fmt.Println(intSlice)
fmt.Println(intSlice.Len())
}