这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天
笔记内容概述
- 变量
- if-else
- for循环
- switch分支结构
- 数组
- map
- rang
- 函数
- 指针
- 结构体
- 结构体方法
- 错误处理
变量
go语言是一门强类型语言,每一个变量都是有自己的变量类型,常见的变量类型有string字符型,int整数型,float浮点型(float(64),float(32)),bool布尔型。
变量声明
go可以通过 var 变量名 = value 的形式来声明变量,例如 var str = "hello,world!",了解过JavaScript的小伙伴是不是感觉和JavaScript的变量生命方式一样呢?但要注意,go是一门强类型语言,而JavaScript是一门弱类型语言,只不过go会自动进行类型推断。go也可以通过 var 变量名 变量类型 = value来声明变量,与大多数编程语言使用 变量类型 name = value 的方式不同,go的变量类型放在变量名后面,例如var str string = "hello,world!,也可以使用 变量名 := value的形式声明变量,例如str := "hello,world!"。
string是go的内置变量类型,和java一样支持使用 "+" 号进行字符串的拼接,如
package main
import "fmt"
func main() {
var str1 = "hello,"
var str2 = "world!"
var str = str1 + str2
fmt.Println(str)
}
注意在编写go的每条语句结束后不需要使用 ";" 进行标识,直接换行即可(go的正式语法是使用";"表示语句的结束的,但这些 ";" 并不会在源码中出现),go的词法分析器会自动插入分号。
常量声明
go的常量声明使用关键字const,如 const aint int = 10,const aint = 10都是可以的,go的常量并没有确切的类型,会在编译期间根据上下文自动推导类型。
if-else
go的if-else语句和其他大多数编程语言类似,只不过go的if-else语句后面不需要使用括号,且循环体必须使用大括号包围(java,c++当循环体只有一条语句时可以不使用大括号包围循环体)例如:
package main
import "fmt"
func main() {
var a = 10
if a == 10 {
fmt.Println("a是", a)
a = 20
}
if a == 20 {
fmt.Println("a现在是", a)
} else {
fmt.Println("a既不是10也不是20")
}
}
for循坏
go中没有while循环,do-while循环,只有唯一的for循环。
for的条件参数什么都不写的话,就是一个死循环,例:
package main
import "fmt"
func main() {
for {
fmt.Print("go")
}
}
for的经典三段句,例:
package main
import "fmt"
func main() {
for i := 0; i < 10; i++ {
fmt.Print(i, " ")
}
}
for使用单条件判断,例:
package main
import "fmt"
func main() {
var i int = 0
for i < 10 {
fmt.Print(i, " ")
i++
}
}
go的for循环中也可以使用break跳出循环,continue继续执行循环。
switch分支结构
go的switch分支结构非常强大,甚至可以取代if-else语句,其后面也不需要使用"()"包围变量,switch支持任意变量类型进行判断,如string,int,float,bool,和结构体变量,当不使用任何变量时,会判断每个分支,和java,c++不同的是,go的switch分支得到一个case满足后就会跳出整个switch(java,c++如果不在case语句最后加上break的话会继续执行后面的case)。
package main
import (
"fmt"
)
func main() {
a := 10
switch a {
case 5:
fmt.Println("a为5")
case 10:
fmt.Println("a为10")
default:
fmt.Println("no more")
}
switch {
case a != 20:
fmt.Println("a不是20")
default:
fmt.Println("unknown")
}
}
数组
go的数组的声明方式为 var 数组名 []数组类型 = value,如果在声明时就对数组进行初始化时需要在大括号前面使用[]数组类型,如:var aint []int = []int{1,2,3,4},数组是在地址上连续且长度不可变,但可使用切片slice来替换数组,slice是长度可变的数组,它实际上就是一个指向数组的指针和一个数组长度,当数组需要变长时,实际上是通过把指针指向一个更长的长度不可变的数组,并把原来数组的值也一并拷贝过来来实现变长数组。
package main
import "fmt"
func main() {
var aint []int = []int{1, 2, 3, 4}
fmt.Println(aint)
aslice := make([]string, 2)
aslice = []string{"A", "B", "C", "D", "E"}
fmt.Println(aslice)
}
map
map也是通过make来声明的,make(map[键类型]值类型),如:amap:=make(map[string]int)声明了一个key为string类型,value为int类型的map,map中的元素都是无序的,通过map[key] = value的方式可以给key赋值,通过map[key]的方式可以读取该key对应的值,通过delete(map名字,key)可以删除指定的key-value对。
package main
import "fmt"
func main() {
amap := make(map[string]int)
amap["A"] = 1
amap["B"] = 2
fmt.Println(amap)
v, e := amap["A"]
fmt.Println(v, e)
delete(amap, "A")
fmt.Println(amap)
}
rang
go的rang可以用来给数组或map进行遍历,rang会返回两个值,对于数组第一个值是索引,第二个值是该索引对应的值,对map来说第一个值是key,第二个值是key对应的value。
package main
import (
"fmt"
)
func main() {
tarray := []int{1, 23, 4, 5, 6}
for k, v := range tarray {
fmt.Println(k, ":", v)
}
amap := make(map[int]string)
amap[1] = "a"
amap[2] = "b"
amap[3] = "c"
for k, v := range amap {
fmt.Println(k, ":", v)
}
}
函数
go函数使用func关键字来声明,声明方式:func 函数名(参数) 返回值类型,例如:func sum(a int,b int) int,如果不声明任何返回值类型,则认为该函数不需要返回值,go函数支持返回多个函数。
package main
import (
"fmt"
)
func main() {
fmt.Println(sum(10, 5))
a, b := returnMore(10, 5)
fmt.Println(a, b)
}
func sum(a int, b int) int {
return a + b
}
func returnMore(a int, b int) (c, d int) {
return a, b
}
指针
声明方式: var 指针名 *指针类型,如:var a *int申请了一个int类型的指针,go的指针的功能非常受限,一般用来在函数中作为参数,因为函数的参数都是拷贝的副本,对参数进行修改并不会对原值有影响,由于使用指针避免了参数的拷贝,所以对性能有一定的帮助。
package main
import "fmt"
func main() {
a, b := 10, 5
fmt.Println(a, b)
exchange(&a, &b)
fmt.Println(a, b)
}
func exchange(a *int, b *int) {
temp := *a
*a = *b
*b = temp
}
传递指针作为参数时,如果即将传递的参数并不是指针时,需要使用 &取地址符 进行传参,这和c++一样。
结构体
go结构体的定义方式为:tyep 结构体名称 struct{},通过 " . "来访问结构体里的变量或方法,或对变量进行赋值初始化。
package main
import "fmt"
func main() {
per := person{}
per.name = "asjun"
per.age = 21
fmt.Println(per)
}
type person struct {
name string
age int
}
在声明时也可以通过{属性名:值}的方式进行初始化,多个属性用" , "分隔。
结构体方法
go虽然没有类的概念来定义类方法,但是通过结构体方法也能实现相同的功能。
go结构体方法定义方式:func (要定义方法的结构体名称) 方法名(参数) 返回值,和普通方法很像,只不过在func关键字后面指明一个结构体的名称,如果紧跟着的是结构体的变量,就可以在该方法内操控这个变量,通过设置结构体指针变量就可以在方法内获得指向自身的指针。
package main
import "fmt"
func main() {
pson := person{}
pson.aMethod()
pson.setNameAndAge("asjun", 21)
fmt.Println(pson)
fmt.Println(pson.matchName("asjun"))
}
type person struct {
name string
age int
}
func (person) aMethod() {
fmt.Println("这是结构体方法")
}
func (pson person) matchName(name string) bool {
return pson.name == name
}
func (this *person) setNameAndAge(name string, age int) {
this.name = name
this.age = age
}
错误处理
go通过返回多参数的特性来直接返回错误,go的错误处理相比java等非常的方便,也更容易定位到发生错误的代码。如除0错误:
package main
import (
"errors"
"fmt"
)
func main() {
v, e := division(10, 0)
if e != nil {
fmt.Println(e)
return
}
fmt.Println(*v)
}
func division(a int, b int) (result *int, err error) {
if b == 0 {
return nil, errors.New("除0错误")
}
var res int = a / b
return &res, nil
}
以上就是go的必知基础知识,可能还有很多知识点并没有记下,小伙伴们可自行百度,或在评论区留言。
共勉!