Golang学习

GoLang学习笔记

记录自己的学习笔记——第一弹!参考资料——《Go web编程》

基础语法

变量

1.1go使用var关键字定义变量,将变量类型放于变量名后面

var variableName type
​
例子:var name string

1.2定义变量时可以定义多个一起,以及初始化他们

定义多个变量
var vname1,vname2,vname3 type
定义单个变量并初始化
var vname = value
定义多个变量并初始化(变量类型一致时可以省略类型)
var vname1,vname2,vname3 type = value1,value2,value3
省略变量类型
var vname1,vname2,vname3 = value1,value2,value3 
终极简化——用:=符号代替var和type
vname := value

限制:在函数外部使用var定义变量会编译不通过,因此通常用var定义全局变量

1.3特殊点

(1) _下划线为一个特殊的变量名————————任何赋予它的值将被丢弃掉
(2) go语言中对于已声明但未使用的变量会在编译期间报错

常量

在程序编译阶段就确定下来的值,而程序在运行时则无法改变该值

2.1go语言用const关键字定义常量,常量可定义为数值、布尔值或字符串等类型

const constantName = value
例子:
const a = 2021
const b = true
const c = "golang"

内置基础类型

3.1布尔型

go语言中布尔型用bool表示,值为true或false,默认为false

3.2数值类型

(1)整数类型分:有无符号和带符号两种。
    go同时支持int和uint,这两种类型的长度相同,但具体长度取决于不同编译器的实现。
    当前的gcc和gccgo编译器在32位和64位平台上都使用32位来表示int和uint,但未来在 64 位平台上可能增加到 64 位。
    go里面也有直接定义好位数的类型:int8, int16, int32, int64和uint8, uint16, uint32, uint64。
    另外存在rune代表int32的别称,byte代表uint8的别称
(2)复数————默认类型是complex128 64位实数+64位虚数)
    形式:RE + IMi (RE是实数部分,IM是虚数部分,而最后的i是虚数单位)

注意点:变量之间不允许互相赋值或操作,不然会在编译时引起编译器报错

3.3字符串

(1)go中的字符串都是采用UTF-8字符集编码。
(2)字符串是用一对双引号("")或反引号(` `)括起来定义,它的类型是string

注意点: 1.go中字符串不可变,但可进行切片操作

2.可以使用+操作符来连接两个字符串

3.4错误类型

go内置有一个error类型,专门用来处理错误信息,go的package里面专门用一个包errors来处理错误

技巧:

定义多个常量或变量时可以进行分组定义
​
例子1:
​
package main
​
import "fmt"
​
func main() {
​
    const (
        a = iota
        b
        c = iota
        d
    )
    
    var(
        e = 20
        f = "golang"
        g = 200.1
    )
​
​
    fmt.Print("\n")
    fmt.Print(a)
    fmt.Print("\n")
    fmt.Print(b)
    fmt.Print("\n")
    fmt.Print(c)
    fmt.Print("\n")
    fmt.Print(d)
​
    fmt.Print("\n")
    fmt.Print(e)
    fmt.Print("\n")
    fmt.Print(f)
    fmt.Print("\n")
    fmt.Print(g)
​
}
输出:
0
1
2
3
20
golang
200.1
​
​
例子2:
​
package main
​
import "fmt"
​
func main() {
    const (
        a  = 2
        b
        c = iota
        d
    )
    var(
        e = 20
        f = "golang"
        g = 200.1
    )
​
​
    fmt.Print("\n")
    fmt.Print(a)
    fmt.Print("\n")
    fmt.Print(b)
    fmt.Print("\n")
    fmt.Print(c)
    fmt.Print("\n")
    fmt.Print(d)
​
    fmt.Print("\n")
    fmt.Print(e)
    fmt.Print("\n")
    fmt.Print(f)
    fmt.Print("\n")
    fmt.Print(g)
​
}
输出:
2
2
2
3
20
golang
200.1
​
注意点:
(1)当分组定义变量或者常量时,第一个常量或变量默认为0索引位上的值,直到遇到显式赋值或者iota,才会改变该位置上的值,否则后一个变量或者常量的值均为前一个索引位上的值
(2)当遇到iota时因为每次调用iota会进行自增,所以尽管后一个的值仍旧等于前一位的值,但是会进行+1处理

go语言默认设计规则

(1)大写字母开头的变量是可导出的,也就是其它包可以读取的,是公用变量;小写字母开头的就是不可导出的,是私有变量。
(2)大写字母开头的函数也是一样,相当于class中的带public关键词的公有函数;小写字母开头的就是有private关键词的私有函数

容器

array

定义:
var arr [n]type——————在[n]type 中,n 表示数组的长度,type 表示存储元素的类型
​
简写:
arr1 := [4]int{1,2,3,4}
​
arr2 := [...]int{9,9,9}——————————go会自动根据元素个数来计算数组长度
​
多维数组:
arr3 := [2][3]int{{1,2,3},{4,5,6}}
​
操作:
(1)两个数组之间的比较需要借助于reflect.DeepEqual(arr1,arr2)来进行比较
(2)数组之间的赋值是值的赋值,即当把一个数组作为参数传入函数的时候,传入的实际上是
该数组的副本,而不是它的指针
(3)值得注意的是,由于数组长度及类型参与了数组的构建,所以二者只要存在其一不一致的两个数组,比较时均返回false,只有数组长度和类型一模一样时才会返回true

slice

概念:引用类型。slice总是指向底层array
​
定义:
var arr []type——————type表示存储元素的类型(和声明array一样,只是少了长度)
​
结构:
{   
    指针
    当前长度
    最大长度
}
​
操作:
(1)可以从现有数组中截取
    arr := [5]int{1,2,3,4,5}
    s := arr[2:5]
(2)便捷操作要领
    slice的默认开始位置是 0,ar[:n]等价于 ar[0:n]
    slice的第二个序列默认是数组的长度,ar[n:]等价于 ar[n:len(ar)]
    如果从一个数组里面直接获取slice,可以这样 ar[:],因为默认第一个序列是 0,第二个是数组的长度,即等价于 ar[0:len(ar)]
​
内置函数:
    len获取slice的长度
    cap获取slice的最大容量
    append向slice里面追加一个或者多个元素,然后返回一个和slice一样类型的slice
    copy函数copy从源slice的src中复制元素到目标dst,并且返回复制的元素的个数
注意:
    append函数会改变slice所引用的数组的内容,从而影响到引用同一数组的其它slice。但当slice中没有剩余空间(即(cap-len) == 0)时,此时将动态分配新的数组空间。返回的slice数组指针将指向这个空间,而原数组的内容将保持不变;其它引用此数组的slice则不受影响

map

概念:
    键值对
​
定义并初始化:
    方法一:
    m := make(map[keyType] valueType)
    添加元素:
    m[keyType] = valueType
    
    方法二:
    var n map[keyType] valueType
    n = make(map[keyType]valueType)
    n[keyType] = valueType
    
    方法三:
    k := map[keyType] valueType{keyType:valueType,...}
​
需要了解:
    map是无序的,每次打印出来的map都会不一样,它不能通过index获取,而必须
通过 key 获取
    map长度不固定,和slice一样,也是一种引用类型
    内置的len函数同样适用于map,返回map拥有的key的数量
    map的值可以很方便的修改,通过 变量名[key]=val 可以很容易的把key为新的val
    map的初始化可以通过key:val的方式初始化值,同时map内置有判断是否存在key的方
式
​
删除元素:
    delete(变量名, key) 

new和make区别

暂时理解不透彻,后续补进

流程控制和函数

if

规范:
    go语言中if条件判断语句不需要使用括号
    条件判断语句里面允许声明一个变量,这个变量的作用域只能在该条件逻辑块内,其他区域无作用
​
例子:
​
if x > 10 {
    fmt.Println("x is greater than 10")
} else {
    fmt.Println("x is less than 10")
}
​
​
if x := computedValue(); x > 10 {
    fmt.Println("x is greater than 10")
} else {
    fmt.Println("x is less than 10")
}
//这个地方如果这样调用就编译出错了,因为 x 是条件里面的变量
fmt.Println(x)

goto

 概念:
 使用goto跳转到必须在当前函数内定义的标签,标签名是大小写敏感的
 
 例子:
 func myFunc() {
    i := 0
 Here: //这行的第一个词,以冒号结束作为标签
    println(i)
    i++
    goto Here //跳转到 Here 去
}

for

语法:
for expression1; expression2; expression3 {
    //...
}
解析:
1.expression1、expression2和expression3均为表达式
2.其中expression1和expression3是变量声明或者函数调用返回值之类的
3.expression2是用来条件判断
4.expression1在循环开始之前调用,expression3 在每轮循环结束之时调用
​
操作:
1.循环里面有两个关键操作 break 和 continue
​
    break操作是跳出当前循环,continue是跳过本次循环(当嵌套过深的时候,break 可以配合标签使用,即跳转至标签所指定的位置)
​
2.break和continue还可以跟着标号,用来跳到多重循环中的外层循环
​
3.for配合range可以用于读取slice和map的数据
例子:
for k,v:=range map {
    fmt.Println("map's key:",k)
    fmt.Println("map's val:",v)
}
​
注意:
由于go支持 “多值返回”, 而对于“声明而未被调用”的变量, 编译器会报错, 在这种较为矛盾的情况下,可以使用_来丢弃不需要的返回值
例子:
for _, v := range map{
    fmt.Println("map's val:", v)
}

switch

语法:
switch index {
case expr1:
    todo something
case expr2:
    todo something
case expr3:
    todo something
default:
    todo something
}
​
规则:
(1)index和expr1、expr2、expr3的类型必须一致。
(2)go的switch非常灵活,表达式不必是常量或整数,执行的过程从上至下,直到找到匹配项;而如果switch没有表达式,它会匹配true
(3)可以多值聚合在了一个case里面,同时,go语言中switch默认相当于每个case自带break,匹配成功后不会自动向下执行其他 case,而是跳出整个switch,但是可以使用 fallthrough 强制执行后面的 case 代码
​
例子:
i := 10
switch i {
case 1:
    fmt.Println("i is equal to 1")
case 2, 3, 4:
    fmt.Println("i is equal to 2, 3 or 4")
case 10:
    fmt.Println("i is equal to 10")
fallthrough //继续执行default
default:
    fmt.Println("All I know is that i is an integer")
}

函数

概念:函数是go里面的核心设计,它通过关键字func来声明
​
多返回值:
    关键字 func 用来声明一个函数funcName
    函数可以有一个或者多个参数,每个参数后面带有类型,通过,分隔
    函数可以返回多个值
    如果只有一个返回值且不声明返回值变量,可以省略包括返回值的括号
    如果没有返回值,那么就直接省略最后的返回信息
    如果有返回值, 那么必须在函数的外层添加 return 语句
​
变参:
    类型相等的情况下变量参数数量可变
        func myfunc(arg ...int) {}
​
传值和传指针:
    传值:
    当我们传一个参数值到被调用函数里面时,实际上是传了这个值的一份副本,当在被调用函数中修改参数值的时候,调用函数中相应实参不会发生任何变化,因为数值变化只作用在副本上
    传指针:
    传指针可以修改被传指针所对应的值,利于多个函数可以修改同一个对象,且传指针比较轻量级(8bytes),如果被传对象是较大的结构体时,建议直接传指针
​
defer:
    当defer被声明时,其参数就会被实时解析(就是defer修饰的语句或变量不会因为后续的代码改变而改变,就是相当于临时记录板,需要在return后执行)
    defer修饰的语句或变量执行顺序为先进后出————————栈
    defer可以读取有名的返回值
​
函数作为值、类型
    在go中函数也是一种变量,可以通过type来定义它,它的类型就是所有拥有相同的
参数,相同的返回值的一种类型
    在写一些通用的接口时,较为实用
​
Panic和Recover:
    panic抛异常(报告致命错误的一种方式,panic异常发生时,程序会中断运行)
    Recover能够将panic转换成可处理的错误
    例子:
    func throwsPanic(f func()) (b bool) {
        defer func() {
            if x := recover(); x != nil {
                b = true
            }
        }()
        f() //执行函数 f,如果f中出现了panic,那么就可以恢复回来
        return
    }
​
main函数和 init函数:
    下图为main函数引入包初始化流程
        简单总结就是从main函数入,通过import加载子包,在加载子包的时候根据const->var->init()的逻辑进行加载,子包加载完成之后返回上一层进行相同的流程,最后返回到main函数进行exit

struct类型

struct
概念:
声明新的类型,作为其它类型的属性或字段的容器
语法:
    type typeName struct{
    
        attribute1 attributeName
        attribute2 attributeName
        attribute3 attributeName
        ......
    }
​
struct的匿名字段
语法:
    type typeName struct{
    
        attribute1  匿名字段,默认该结构体包含了attribute1的所有字段
        attribute2 attributeName
        attribute3 attributeName
        ......
    }
作用:
    (1)能够实现字段的继承,以及可以以属性字段来进行访问
        typeName.attribute1 = attribute1{...}
        这样就可以进行typeName.attribute1.attribute1属性,从而进行访问
    (2)可以利用匿名字段进行访问和修改字段,较为实用
    (3)如果匿名字段的内部属性和平行属性出现重复字段,则可以通过属性字段来访问
        
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值