“这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天
ps:本人的笔记多以代码的形式呈现,可以在注释中查看到详细的解释
基础知识
变量定义
变量类型:字符串(string,内置型,可以直接+,=等),整数(int32),浮点型(float64(默认)||float32),布尔型,复数类型(complex128),字符类型(默认rune),数组,切片,map,指针类型,错误类型(error类型,默认值是nil)
变量以及变量声明方式
单个变量声明:
var name=value //该方法会自动判断变量的类型
var name type = value //显式地写出变量的类型
var name = type(value) //通过显式类型转换赋值
name := value //短变量声明方式,建议在局部变量定义并且需要指定初始值的时候使用
var name type //定义未初始化的变量,一般用于定义暂时不需要初始化的局部变量
const name (type) = value //定义常量,没有类型,根据变量的的值进行判断,也可以加类型,常量不能使用 :=来定义
err := nil
变量块声明:
var{
name1 type = value1
name2 type = value2
....
}
变量行声明:
var name1, name2, name3 =value1, value2, value3
name1, name2, name3 := value1, value2, value3
var{ //变量行的定义块
name1, name2, name3 =value1, value2, value3
name4, name5, name6 =value1, value2, value3
}
条件语句
if-else:可以类比于传统的C/C++中的if-else
if value1 { //单条件if
语句
}else{
语句
}
if 语句1; value2{ //在if前面添加语句,先执行语句然后再执行判断条件value
}else if value3{
}
if 语句2; value1 && value2{ //一个执行语句两个判断条件
}
循环语句
for:与传统的C/C++中的for循环也是类似的,for中的三个语句都是可以省略的,此时就相当于while(true)
for i:=0; i<n; i++{ //常规写法
语句
}
//变形写法
i:=1
for i<n{
语句
i++
}
//死循环
for{
语句
}
for...range...:每次获取一对数,下标和数值,for只能通过下表获取元素,可以遍历切片、数组、字符串、Map、Channel
for index, value:=range arrayTest{ //在这里需要注意,如果直接修改value的值是不能够修改对应array Test的值的,因为是copy过来的,必须通过下标访问
语句
}
switch分支结构
所有的case语句后面的常量值都不允许有重复,否则就会报错,并且在switch之后可以接需要执行的句子,然后再接分支变量,使用分号隔开即可 case 1: 语句
switch (语句;)name{ //一般的switch语句,name可以是任何变量
case value1, value2, value3 : 语句 //case多种情况进行同样的操作
case 3: 语句
case 4: 语句
default: 语句
}
//可以用于多个if--else的替代
switch (value){ //()内的value是可以省略的,此时则会判断case语句中的条件,一旦为真就会执行
case condition1 && condition2 ||....: 语句1
case ....
case ....
fallthrough //不执行默认的跳出switch操作,直接执行下一个case(此时就不会判断case了,而是直接执行语句)
case ....
}
GO中的break与continue
GO中的break语句和continue语句基本用法可以参考java中的用法,既能退出循环又能跳到指定位置
label1:
for{
switch value{
if value<0 {
break; //跳出switch循环
}
case 1: break label1 //直接跳到label,相当于goto
}
}
数组
数组在go语言中用的比较少,主要原因还是在于数组的长度固定,不太适合数据的动态交互
var name[length]type //定义未初始化的数组
name :=[...]{values} //定义数组并且初始化
name[1]=value //使用下标修改数组
//遍历数组
for i:=0; i<len(array); i++{ //一般的for遍历
...
}
for i, value := range array{ //使用range遍历
...
}
切片
定义:任意长度的数组,可以更改长度,可以类比于STL中的vector函数,切片也可以遍历,方式和数组一样
切片的定义和初始化
var name[]type //定义切片
var number=make([]type,length) //定义初始长度为length的切片
name :=make([]type, length) //同上
arr := [...]type{values} //使用数组初始化
切片的常用方法
n= cap(number) //求出切片的容量
name=append(name, value) //在切片的最后插入元素并且返回新的切片
copy(number, name) //将name中的值复制到number当中
//切片的切片操作
fmt.Println(name[value1: value2]) //输出下标从value1到value2的全部数据,遵循取左不取右的原则,不会输出value2下表的值,省略value1或者value2的时候会直接从开头开始取或者一直取到结尾
number2 := name[0:3] //切片赋值,number2成为一个新的切片
s = number ; //赋值操作,此时对s进行的操作都会与number同步
从切片中删除元素
公式:要从切片a中删除索引为index的元素,则执行操作append(a[:index],a[index+1:])
s :=[]int{23,43,23,43,53,43,34,54}
s = append(s[:2],s[3:]) //删除元素23
map
可以参考python中的字典,两者具有类似性
声明方式汇总
name :=make{map[keyvalue]type} //定义一个关键字为keyvalue,类型为type的map
var name map[keyvalue]valuetype
map的基本数据操作
name[keyvalue] = value //修改操作
value, jude := map[keyvalue] //判断keyvalue的键值存不存在,存在jude为true
map的遍历
for key := range name{ //遍历key
.....
}
for key, value := range name{ //遍历关键字和值
......
}
指针
指针在go中的主要用途就是实现函数对外部变量的修改,即类似于C++中的引用变量,在这里需要记住,go中的赋值操作与copy操作是不一样的,赋值会指向同一地址,改变一个会改变所有
number := 3
func function(name *int)(){
name+=1
}
function(&number)
fmt.Println(numer) //输出4、
var ptr[3] *int //定义指向数组的指针
a :=[]int{1,2,3}
for i :=0 ;i < 3; i++{
ptr[i] = &a[i]
}
fmt.Println(ptr) //输出1 2 3
结构体
结构体类似于C/C++中的结构体,但是赋初值的方式略有不同,ps:结构体作为函数参数的时候也会有指针和非指针两种用法
type name struct{
name1 type
name2 type
name3 type
}
//初始化1(部分成员初始化)
a := name{name1:value1, name2:value2} //name3没有传入,那么就会直接设置默认空值
//初始化2(所有成员初始化
a := name{value1, value2, value3}
//初始化3(使用new关键字创建结构体指针)
var a = new(name)
a.name1 = value3 //通过.运算符访问结构体变量
匿名结构体
不给结构体实际的变量名即为匿名结构体
var name struct{
...
}
name.value = value //临时使用结构体,故而可以不用对结构体起名字(a := name)
结构体方法
类似于类方法,也可以通过(.)运算符进行调用
type name struct{
name1 type
name2 type
}
func (p name)functionname(){ //定义结构体方法,如果第一个括号是p *name那么方法内就可以直接修改结构体的值
p.name1=....
}
a :=name{name1: value1}
a.functionname() //调用结构体方法
错误处理方式
go中对错误的处理方式是对目标语句进行判断,如果输出了nil那么就对nil进行判断
func function ()(number int, err error){
err, value :=f(3,4)
if err==nil{
fmt.print(err)
return
}
}
打印
对于不同类型的变量,go统一使用%v表示,不同的输出要求有不同的输出格式符
fmt.Printf("%v", name) //打印值
fmt.Printf("%+v", name) //打印变量名:值
fmt.Printf("%#v", name) //打印变量的类型 变量名:值
fmt.Printf("%.nf", name) //控制打印位数
时间处理
使用import time中的各种方法
import{
"time"
"fmt"
}
now := time.now() //获取当前时间
fmt.Printf(now)
now.format("2006-01-02 15:23:09") //格式化成标准样式
fmt.Printf(now.Unix) //获取时间冲
字符串转数字
依靠strconv中的方法进行转换
import{
"fmt"
"strconv"
}
n, _ :=strconv.ParstInt("目标字符串", 字符串的进制(0代表自己判断, 精度) //字符串转数字
fmt.Printf(n)
n, _ := strconv.Atoi("目标数字") //数字转字符串
GO--函数
函数的特性
- 函数分为:普通函数,匿名函数,方法
- go当中不允许重载函数(但是可以重写)
- 除了匿名函数以外,所有的函数都不能互相嵌套
- 函数是一个值,可以赋值给变量,让这个变量也变成函数
- 函数可以作为函数的参数
- 函数可以作为函数的返回值
- 函数的参数可以没有名称
- 函数可以返回多个值
- 在函数中的返回值是实现定义好的,可以直接再函数体中使用
函数的定义和用以及返回值
函数的定义:
func functionname (valuename1 type, valuename2 type) [returnvalue1 type, returnvalue type]{
//函数体
}
函数的调用:
ans1, ans2 = functionnaem(value1, value2)
函数的返回值:
func function()(ans int){
name : = "字节跳动"
age := 99999
net =int32(87)
return net //返回单个参数
}
func function()(ans int, ans2 string){
name : = "字节跳动"
age := 99999
net =int32(87)
return net, name //返回多个参数
}
func function()(ans int, ans1 string){
name : = "字节跳动"
age := 99999
net =int32(87)
return //没有指定返回的参数,并且函数体中也没有使用到返回值变量ans和ans1,所以没有返回值
}
func function()(ans int, ans1 string){
ans1 : = "字节跳动"
ans := 99999
net =int32(87)
return //直接返回ans1和ans因为函数中使用这两个参数并且对其进行了初始化
}
func add(x, y int)int{
return x+y
}
func sub(x, y int)int{
return x*y
}
func call(s string)func(int, int)int{
switch s{
case "+":
return add //函数作为返回参数
case "*":
retuern sub
default:
return nil //返回错误(error变量的默认值)
}
}
函数的参数
map、slice、interface、channel这些数据类型本身就是指针类型的,所以就算是作为参数拷贝也会影响到原本的值,即相当于引用变量
package main
import {
"fmt"
}
//切片等作为参数
func function( name[] int){ //切片作为参数
}
//长参数
func function(ans int, ans1 string, ans3...int){ //最后一个为可变参数,数量不确定
for _, v := range ans3{ //对其中的元素进行访问
}
ans[2] = 90 //直接使用下标访问,但是要注意越界
}
//函数作为参数
func function(name string)(){
fmt.Println(name)
}
func function1(name string, f fun(string)){ //函数作为参数
f(name)
}
函数类型的变量
函数的变量类型可以是:一般参数,结构体,指针,函数,结构体指针等等
package main
import "fmt"
type fun func(int, int) int //定义一个函数类型的变量
func sum(a int, b int) int {
return a + b
}
func max(a int, b int) int {
if a > b {
return a
} else {
return b
}
}
func main() {
var f fun
f = sum //函数作为变量赋值
s := f(1, 2)
fmt.Printf("s: %v\n", s)
f = max
m := f(3, 4)
fmt.Printf("m: %v\n", m)
}
匿名函数
go语言函数不可以嵌套,但是匿名函数可以嵌套,在函数内部可以定义匿名函数来进行一些处理和操作,可以参考一下java中的匿名内部类
//语法格式
func(参数列表)(返回值) //参数返回值都可省略
func main(){
a :=func(a int, b int)int{ //定义匿名函数
if a>b{
return a
}else{
return b
}
}
i := max(1,2)
fmt.Printf(i)
}
本次学习的感受
学习完相应的内容之后,我对go语言有了更加深入的了解,其实go语言并没有我想象的那么难,他更像是C++,AVA和python的结合体,基本的底层原理像if else for等等基本是与C++类似,而像对数据类型的高级操作,例如切片格式化,等等就与python中的数据处理方式类似,而对于变量的赋值指针以及copy函数的处理方式,则与JAVA中类似,够语言就像是一个容器集合的各种常用语言的优点。这其中,最让我震惊的当属switch语句,我从来没有想过switch语句原来可以巧妙的使用,并且来代替连续的嵌套if语句,使整个项目以及代码更具有可观性和可维护性,这是我第一次接触go语言,也希望之后的学习中能够对go语言有更深刻的理解和感悟,争取在青训营期间收获自己想要的东西