go语言基础

发布时间:2026/7/19 23:18:00

go语言基础 语法注意事项源文件以go为扩展名程序执行入口是main函数严格区分大小写方法由一条条语句构成每个语句后不需要分号go语言会在每一行后面自动加分号go编译器是由一行行进行编译的因此一行就写条语句不能把多条语句写在同一行定义的变量或者import 的包如果没有使用到代码不能编译通过大括号都是成对出现的缺一不可一行最长超过80个字符超过要换行fmt.Println(aaaaaaa,aaaaaaaa,aaaaaaaa)go语言结构go语言的基础组成包声明引入包函数变量语句 表达式注释package main //包声明 import fmt //引入包 func main(){ //程序执行函数 fmt.Println(Hello World) //输出内容 }执行go程序在终端上执行 go run go文件用go build 命令生成二进制文件go语言基础语法go标志go程序由许多标志组成关键字、标志符、常量、字符串、符号行分割go程序每一行代表一个语句在编译的时候自动生成号。故不用加分号多个语句不可以在同一行若要在同一行需要分号隔开注释行注释 // 快捷键 CTRL 块注释/* 内容 */标识符标识符用来命名变量、类型等程序实体无效标识符以数字开头go语言关键字有运算符字符串连接通过号连接fit.Println(helloworld)关键字var 定义变量 //可以省略声明类型var a intvar b stringvar c byteconst 定义常量const a intconst b stringconst c bytego语言空格空格常用于分割标识符、关键字、运算符、和表达式增加代码的可读性也可以不加空格格式化字符串Sprintf生成格式化字符串后返回该字符串var afmt.Sprintf(a:%db:%s,1,sss) //先格式化再写入a中 fmt.Println(a) //输出aPrintf生成格式化字符穿后写入标准输出fmt.Printf(a:%db:%s,1,sss) //直接输出 //新建变量加赋值 //只有赋值go语言数据类型数据类型用于声明函数和变量布尔型是可以是常量true 或者 falsevar b bool true数字类型整数型无符号类型uint8 uint16 uint32 uint64有符号类型int8 int 16 int 32 int64可以直接用int浮点型float32 float64复数型 complex64 complex128注意必须标注位数其他数字类型byte 类似于 uint8rune 类似于int32int 与uint一样大uintptr 无符号类型用于存放一个指针字符串类型使用uft-8编码标识Unicode文本派生类型指针类型Pointer数组类型结构化类型structChannel类型函数类型切片类型接口类型Map类型go语言变量变量名由数字、下划线、字母组成数字不能放在首位声明变量的一般形式使用var关键字var 变量名 变量类型一次可以声明多个变量var 变量1,变量2,... 变量类型变量声明指定变量类型如果没有初始化则变量默认为零值默认值数值类型为0布尔类型为false字符串为“”空字符串其他为 nil根据值自行判定变量类型var v_name value使用:声明变量v_name : value 相当于 var v_name; v_name value;注意如果变量已经使用var声明过了在使用 : 声明变量就会产生编译错误多变量声明//类型相同多个变量, 非全局变量var vname1, vname2, vname3 typevname1, vname2, vname3 v1, v2, v3// 和 python 很像,不需要显示声明类型自动推断var vname1, vname2, vname3 v1, v2, v3// 出现在 : 左侧的变量不应该是已经被声明过的否则会导致编译错误vname1, vname2, vname3 : v1, v2, v3// 这种因式分解关键字的写法一般用于声明全局变量var (vname1 v_type1vname2 v_type2)值类型与引用类型值类型使用等号将一个变量的值赋值给另一个变量引用类型引用类型的变量储存的是变量的值所在的存储地址或存储地址中第一个字所在的位置这个内存地址称为指针同一个引用类型的指针的多个字可以是在连续的内存地址中也可以将这些字分散在内存中引用类型赋值是将地址复制如果被引用变量的值修改了所有引用他的值也会被修改go语言常量常量是一个简单值的标识符在程序运行是不可以修改可以是 数字型、布尔型、字符串型基本语法与参数常量定义格式 const 常量名 类型 常量值类型可以省去定义方式显示类型定义const b string abc:隐式类型变量const b abc批量定义const a , b , c v1 , v2 , v3常量组与枚举go语言没有枚举关键字通常使用常量组来实现枚举效果package main import fmt //定义枚举 const ( unknown iota female male ) func main() { fmt.Printf(未知%d,女性%d男性%d, unknown, female, male) }内置函数在使用中的应用常量表达式中可以使用 len() , cap() , unsafe.Sizeof() 等内置函数计算表达式的值注意常量表达式的值必须是内置函数iota常量计数器可以在 const 声明块中自主生成递增的序列值重要特性iota 在 const 关键字出现时将被重置为 0const 中每新增一行常量声明iota 自动计数加一const 语句块中的索引从0开始package main import fmt func main() { const ( a iota // 0 b // 1 c // 2 d ha // 独立值iota 1 e // haiota 1 f 100 // 独立值iota 1 g // 100iota 1 h iota // 7恢复使用 iota 值 i // 8 ) fmt.Printf(a%d, b%d, c%d, d%s, e%s, f%d, g%d, h%d, i%d\n, a, b, c, d, e, f, g, h, i) }package main import fmt const ( i 1 iota // 1 0 11*2^0 j 3 iota // 3 1 6, 3*2^1 k // 3 2 12, 3*2^2 l // 3 3 24 , 3*2^3 ) func main() { fmt.Printf(i%d, j%d, k%d, l%d\n, i, j, k, l) }go语言运算符1.算数运算符自增 自减 --2.关系运算符3.逻辑运算符与或||非4.位运算符运算符描述参与运算的两个数对应的二进制位相与|参与运算的两个数对应的二进制位相或^参与运算的两个数对应的二进制位相异时结果为1左移运算符左移n位是乘以2的n次方。是将数的二进制全部左移n位高位丢弃低位补0右移运算符右移n位是除以2的n次方。是将数的二进制全部右移n位低位丢弃高位补05.赋值运算符 简单的赋值运算运算后赋值的有、-、*、/、%、、、、|、^6.其他运算符 返回变量存储地址 //a 将给出变量的实际地址*指针变量 //*a 是一个指针变量7.运算符优先级优先级运算符5*/ % ^4- | ^3 ! 21||通过使用括号来临时提升某个表达式的整体运算优先级go语言条件语句if语句if else 语句go特有if里面可以先定义变量变量仅在if/else里有效if num : 20; num 10 { fmt.Println(大于10) } else { fmt.Println(小于等于10) }if 嵌套语句switch 语句基础特点go 的 switch 自带 break匹配后自动结束不用手写break支持多条件匹配无表达式 、无表达式、fallthrough 穿透case 可以放表达式、变量、常量基础语法switch 变量 { case 值1: 逻辑1 case 值2, 值3: // 多个条件满足其一就匹配 逻辑2 default: // 都不匹配执行 默认逻辑 }无表达式 switch类似于 if-else 多判断switch 后不写变量等价于 switch true。 case 里写布尔判断case中初始化变量switch 开头可以定义临时变量fallthrough 穿透go 默认不穿透fallthrough 会强制执行下一个caseselect 语句select 语句类似于 switch 语句 但是select会随机执行一个可运行的case。如果case可运行他将会阻塞直到有case可运行基础语法select { case 通道读操作: // 读就绪执行 case 通道写操作: // 写就绪执行 default: // 所有通道都未就绪时执行非阻塞 }有default 时select 可能会发生阻塞没有default 时select 不会发生阻塞超时控制使用 time.After 防止 select永久阻塞package main import ( fmt time ) func main() { ch : make(chan string) select { case res : -ch: fmt.Println(res) case -time.After(2 * time.Second): fmt.Println(等待2秒超时) } }go语言循环语句循环类型for 循环循环嵌套循环控制语句控制语句描述break语句终断当前的for循环或跳出switch语句continue语句跳出当前循环的剩余语句然后继续进行下一个循环goto 语句将控制转移到被标记的语句goto语句基础定义无条件跳转语句直接跳转到同函数内只定义的标签label所在代码行直线控制流转移package main import fmt func main() { i : 0 LOOP: // 定义标签 fmt.Println(i) i if i 3 { goto LOOP // 跳转到LOOP标签 } fmt.Println(结束) }关键约束1.只能在同一个函数里跳转不能跳转到别的函数2.不允许跳过变量声明3.不能从代码外层跳进 if 、 for 等代码块内部4.允许从循环/判断内部跳出到外部标签实用的应用场景break 只能跳出当前的一层循环goto 可直接终止所有的嵌套循环无限循环package main import fmt func main(){ for true{ fmt.Pritf(这是无限循环) } }go语言函数函数是基本的代码块用于执行一个任务go语言至少有个main函数函数的声明需要告诉编译器函数的名字返回类型和参数go语言标准库有许多内置函数函数的定义go语言函数格式func function_name( [parameter list] ) [reture_types ] {函数体}func 函数由func 开始声明function_name函数名称参数列表和返回值构造了成了函数签名paramater_list :参数列表return_types: 返回值类型 //有些函数不需要返回值不是必须的函数体函数定义的代码聚合package main import fmt func max1(a, b int) int { if a b { return a } else { return b } } func main() { var maxn int maxn max1(1, 2) fmt.Println(maxn) }函数调用调用函数时向函数传递参数并返回值同一个go文件内函数的调用无先后顺序同一个包下跨文件调用同一个包下的不同文件下无需前置声明可以直接调用函数首字母权限首字母小写包私有进当前包所有文件可调用首字母大写导函数当前包外部其他包均可以调用挎包调用满足三个条件:被调用包的函数名首字母大写调用函数的文件要导入目标包 // import 项目下包的路径调用格式 包名.函数名()函数参数函数使用的参数该变量称为函数形参形参就像是定义在函数内的局部变量值传递在调用函数时将实际参数复制一份传递到函数上在函数中对参数修改不过会影响实际参数引用传递核心定义引用传递本质吧实参的内存地址传递给函数形参函数内通过地址修改内存里的数据原始实参的值会用不发生改变两个关键符号变量 去变量内存地址*指针变量 解引用操作地址对应的的值package main import fmt // 参数是 int 指针接收地址 func changeNum(n *int) { *n 999 // 通过地址修改原始变量的值 } func main() { a : 10 changeNum(a) // a 取出a的地址传入函数 fmt.Println(a) // 输出 999原值被修改 }函数用法作为另一个函数的实参go中的函数可以像普通函数一样定义、赋值、当作参数传递给其他函数、作为返回值返回把一个函数传递入另一个函数的参数位置就是“函数做实参”先定义函数类型格式: type 类型名 func参数类型 返回值类型// 定义函数类型 calc // 规则必须接收2个int参数返回1个int type calc func(int, int) int目标函数声明该类型参数// compute就是目标函数第三个参数f的类型是calc func compute(a, b int, f calc) int { return f(a, b) } //f calc: 代表参数f 只能满足calc格式的函数调用时满足格式的函数传出去前提要有一个完全匹配calc模板的普通函数再把add直接当作第三个实参传递给目标函数package main import fmt // 第一步定义函数类型定好函数格式标准 type calc func(int, int) int // 第二步目标函数声明calc类型的形参f func compute(a, b int, f calc) int { return f(a, b) } // 符合calc格式的普通函数 func add(x, y int) int { return x y } func main() { // 第三步调用传入满足格式的add函数 res : compute(2, 3, add) fmt.Println(res) }闭包与匿名函数匿名函数没有函数名的函数就叫匿名函数// 格式1定义后立刻调用 func(参数) 返回值 { 逻辑 }(传入实参) // 格式2赋值给变量保存 变量名 : func(参数) 返回值 { 逻辑 }闭包定义捕获了外层局部变量的匿名函数两个必要条件本身时匿名函数匿名函数能访问、修改外层函数的局部变量延长变量生名命周期核心特点闭包会记住外层变量的环境哪怕外层函数执行完毕变量也不会销毁闭包格式// 外层函数返回值为函数类型 func 外层函数名() func(形参) 返回类型 { //闭包类型的返回值类型 func(形参 返回值类型 // 外层局部变量被闭包捕获 变量 : 初始值 // 返回匿名函数闭包 return func(形参) 返回类型 { // 操作外层变量 变量 return 变量 } }package main import fmt // 外层函数返回一个闭包 func counter() func() int { num : 0 // 外层局部变量 // 返回匿名函数闭包捕获num return func() int { num //使用并修改了匿名函数外的局部变量 return num } } func main() { f : counter() fmt.Println(f()) // 1 fmt.Println(f()) // 2 fmt.Println(f()) // 3 f2 : counter() fmt.Println(f2()) // 1全新独立变量num }方法定义本质是绑定了接受者的函数格式func (接收者变量 接收者类型 方法名 参数列表 返回值列表{方法逻辑}接收者代表这个方法属于哪一种自定义类型结构体基础自定义类型调用方式变量.方法名接受方式值接收package main import fmt type Person struct { name string age int } // 值接收者 func (p Person) rename(newName string) { p.name newName // 修改的是拷贝出来的副本 } func main() { man : Person{name: 小明, age: 18} man.rename(小红) fmt.Println(man.name) // 输出小明原值没变 }指针接收// 指针接收者 func (p *Person) grow() { p.age // 直接修改原结构体 } func main() { man : Person{name: 小明, age: 18} man.grow() fmt.Println(man.age) // 输出19原值被修改 }go语言变量作用域局部变量在函数体内声明的变量称为局部变量只作用于函数体内参数和返回值变量也是局部变量全局变量在函数体外面的变量称为全局变量全局变量可以在整个包使用注意全局变量与局部变量名字是相同的但是函数内部的变量会优先考虑go语言数组声明数组格式var arrayName [size]dataType初始化数组默认初始化var numbers [5]int //默认初始值都为0var numbers [5]int{1,2,3,4,5}numbers : [5]int{1,2,3,4,5}注意数组的大小是类型的一部分因此不同大小的数组是不兼容的如果数组的长度不确定可以使用...来代替长度编译器会根据元素的个数判断长度访问数组元素通过循环遍历数组元素go语言指针指针变量指向的是一个值的变量地址指针存储变量内存地址的变量两个关键符号变量 取变量内存地址*指针变量 解引用操作地址对应的的值指针使用流程定义指针变量使用前需要声明指针格式var var_name *var-tpyevar_name 为指针变量名*用于指定变量是作为一个指针var-type 为指针类型 *int指向整数型 *float32 指向浮点型为指针变量赋值p num变量取变量内存地址把地址存进指针 p访问指针变量的值*指针变量根据指针存放的地址取出对应对应内存里的数据package main import fmt func main() { var a int 20 /* 声明实际变量 */ var ip *int /* 声明指针变量 */ ip a /* 指针变量的存储地址 */ fmt.Printf(a 变量的地址是: %x\n, a ) /* 指针变量的存储地址 */ fmt.Printf(ip 变量储存的指针地址: %x\n, ip ) /* 使用指针访问值 */ fmt.Printf(*ip 变量的值: %d\n, *ip ) }空指针当一个指针被定义后没有分配到任何变量时它的值为 nilnil 的指针也为空指针nil 指的是零值或空值指针数组概念数组中每个元素都是指针统一类型 *Tpackage main import fmt func main() { a, b, c : 10, 20, 30 // 定义指针数组3个*int元素 var ptrArr [3]*int [3]*int{a, b, c} // 遍历打印地址、解引用值 for i : 0; i 3; i { fmt.Printf(地址%p值%d\n, ptrArr[i], *ptrArr[i]) } // 通过指针修改原变量 *ptrArr[1] 999 fmt.Println(b) // 999 }二级指针指向指针的指针普通变量-一级指针存放变量地址-二级指针存放一级指针地址语法: var pp **intpackage main import fmt func main() { num : 66 var p *int num // 一级指针 var pp **int p // 二级指针存p的地址 fmt.Println(num原值, num) fmt.Println(p存储地址, p) fmt.Println(pp存储p的地址, pp) fmt.Println(*pp p, *pp) fmt.Println(**pp num, **pp) // 二级指针修改原始值 **pp 888 fmt.Println(num) // 888 }函数传递指针参数值传递函数内修改只是副本外部不变指针传递传变量地址函数内解引用直接修改外部原始数据package main import fmt // 接收int指针 func changeVal(x *int) { *x 1000 // 修改原变量 } func main() { n : 10 changeVal(n) // 传入地址 fmt.Println(n) // 1000 }go语言结构体结构体是由一系列具有相同类型或不同类型的数据构成的数据的 集合定义结构体type 结构体名字 struct { meber definition meber definition meber definition ... }定义结构体后就可以用于结构声明格式如下variable_name : 结构体名字 {value1,value2,value3...} variable_name : 结构体名字 { key1: value1, key2 : value2, key3 : value3 }访问结构体成员格式为结构体.成员名package main import fmt type Books struct { title string author string subject string book_id int } func main() { var Book1 Books /* 声明 Book1 为 Books 类型 */ var Book2 Books /* 声明 Book2 为 Books 类型 */ /* book 1 描述 */ Book1.title Go 语言 Book1.author www.runoob.com Book1.subject Go 语言教程 Book1.book_id 6495407 /* book 2 描述 */ Book2.title Python 教程 Book2.author www.runoob.com Book2.subject Python 语言教程 Book2.book_id 6495700 /* 打印 Book1 信息 */ fmt.Printf( Book 1 title : %s\n, Book1.title) fmt.Printf( Book 1 author : %s\n, Book1.author) fmt.Printf( Book 1 subject : %s\n, Book1.subject) fmt.Printf( Book 1 book_id : %d\n, Book1.book_id) /* 打印 Book2 信息 */ fmt.Printf( Book 2 title : %s\n, Book2.title) fmt.Printf( Book 2 author : %s\n, Book2.author) fmt.Printf( Book 2 subject : %s\n, Book2.subject) fmt.Printf( Book 2 book_id : %d\n, Book2.book_id) }结构体作为函数参数可以将结构体类型作为参数传递给函数package main import fmt type Books struct { title string author string subject string book_id int } func main() { var Book1 Books /* 声明 Book1 为 Books 类型 */ var Book2 Books /* 声明 Book2 为 Books 类型 */ /* book 1 描述 */ Book1.title Go 语言 Book1.author www.runoob.com Book1.subject Go 语言教程 Book1.book_id 6495407 /* book 2 描述 */ Book2.title Python 教程 Book2.author www.runoob.com Book2.subject Python 语言教程 Book2.book_id 6495700 /* 打印 Book1 信息 */ printBook(Book1) /* 打印 Book2 信息 */ printBook(Book2) } func printBook( book Books ) { fmt.Printf( Book title : %s\n, book.title) fmt.Printf( Book author : %s\n, book.author) fmt.Printf( Book subject : %s\n, book.subject) fmt.Printf( Book book_id : %d\n, book.book_id) }结构体指针可以定义结构体的指针类似与其他指针变量var struct_pointer *Bookspackage main import fmt type Books struct { title string author string subject string book_id int } func main() { var Book1 Books /* 声明 Book1 为 Books 类型 */ var Book2 Books /* 声明 Book2 为 Books 类型 */ /* book 1 描述 */ Book1.title Go 语言 Book1.author www.runoob.com Book1.subject Go 语言教程 Book1.book_id 6495407 /* book 2 描述 */ Book2.title Python 教程 Book2.author www.runoob.com Book2.subject Python 语言教程 Book2.book_id 6495700 /* 打印 Book1 信息 */ printBook(Book1) /* 打印 Book2 信息 */ printBook(Book2) } func printBook( book *Books ) { fmt.Printf( Book title : %s\n, book.title) fmt.Printf( Book author : %s\n, book.author) fmt.Printf( Book subject : %s\n, book.subject) fmt.Printf( Book book_id : %d\n, book.book_id) }go语言切片切片 slice 十动态数组基于数组封装长度可变底层引用数组go语言切片是对数组的抽象是动态数组切片的长度是不固定的可以追加元素在追加时可能是切片的容量增大定义切片可以使用为指定大小的数组来定义切片var identifier []type使用 make()函数来创建切片var slice1 []type make([]type, len)slice1 : make([]type, len)可以指定容量其中 capacity 为可选参数make([]type,len,capacity)这里 len 是数组的长度也是原始长度capacity 为切片容量切片初始化arr : []int {1,2,3,4}切片: s: arr[start : end : max] //arr[start : end]为左开右闭len 与 cap 函数切片是可以索引的并且可以由len方法获取长度cap方法可以计算容量append 和 copy 函数append为追加函数nums append( nums , a , b, c) //在nums后面追加a,b,ccopy 为拷贝函数copy nums1 nums2 //拷贝 nums2的内容到nums1

相关新闻