菜狗前端的go语言学习笔记(2)
写在文章前
上一篇的go语言开篇已经过去了数月,菜狗前端终于又开始继续学习了。和这个世界说了hello world之后,继续学习go语言的顺序编程。
变量
变量声明
下面的表能说明go 与 js变量声明的不同方式。
| js | go | |
|---|---|---|
| 布尔型 | var isFool = true |
var isFool bool = true |
| 整型 | var i = 10 |
var v1 int = 10(go中包含int8, byte, int16, int,uint,uintptr) |
| 浮点型 | var i = 0.1 |
var pi float64 = 3.1415926,var zero = 0.0(无类型浮点常量), var size float32 = 3(size 为 3.0 ,常量的多重赋值) |
| 复数 | \ | var i complex64 = 3.2 + 12i (complex64 & complex128) |
| 字符串 | var str = 'fdsdfs'; |
var str string = "sdfsdfs" |
| 字符类型 | \ | var s rune |
| 数组 | var arr = [] |
var v3 [10]int |
| 数组切片 | \ | var v4 []int |
| 结构体 | \ | var v5 struct { f int } |
| 指针 | \ (this勉强算?) |
var v6 *int |
| 对象 | var obj = {key : 'value'} |
var v7 map[string] int (key 为string 类型,value 为int类型) |
| 函数 | function myFun() {} |
var v8 func (a int) int |
除上述表格列出的之外,还有几个声明的特性:
- 不需要使用分号作为结束符
- 多个需要声明的变量放置在一起
var (
v1 int
v2 string
)
变量初始化的三种不同方式
var v1 int = 10
var v2 = 10 // 编译器自动推导出类型
v3 := 10 // := 左侧的变量不能被声明后,否则会导致编译错误
变量赋值
-
普通赋值
var v10 int v10 = 123 -
多重赋值
i,j = j,i // 交换两个变量的值 ; 不用再声明一个第三个变量来交换值
匿名变量
go语言允许通过使用多重返回和匿名变量来_来代替可能混淆代码阅读者视线的内容。
func GetName() (firstName, lastNamem, nickName string) {
return 'xiaoming','wang' ,'goudan'
}
// 只想获得nickname
_,_, nickName := GetName()
常量
js 中 在es6以上使用const关键字来声明一个变量为常量,但是其实没有区分常量的类型。Go也是使用const 关键字来声明一个常量。并且Go语言和其他强类型的语言一样,区分 浮点类型,复数类型,布尔类型,字符串类型。但是与C++ 的区别在于,C++ 严格的区分了long类型的常量,和int类型的常量, Go 只要这个常量在相应类型的值域范围内就可以作为该类型的常量。
- 定义
const pi float64 = 3.1415926
const a,b,c = 3,4,"foo"
const fushu = 3.2 + 12i // 复数类型
- 注意:
- 常量定义的右边可以是一个再编译期运算的常量表达式
- 常量的赋值是一个编译期行为,所以如果出现运行期才能得到的表达式,会造成编译错误。
const Home = os.GetEnv("Home")
预定义常量
- go语言中的预定义常量: true, false, iota
- iota 是一个js中没有的概念,他在每一个const关键字出现时被重置为0,在下一个const出现之前,iota没出现一次,代表的数字会自动增加1.
const ( // iota 被设置为0
c0 = iota // c0 的值为0
c1 = iota // c1 的值为1
c2 = iota // c2 的值为2
)
const ( // iota 被设置为0
a = 1 << iota // 1<<1 = 1
b = 1 << iota // 1<<2 = 2
c = 1 << iota // 1<<3 = 4
- 若const 的赋值语句的表达式是一样的,那么可以省略后一个赋值表达式 。使用枚举可以简化赋值代码量
const (
c0 = iota
c1
c2
)
各种类型
布尔类型
var b bool = true
- 注意: 布尔类型不能接受其他类型的赋值,不支持自动或者强制的类型转换,否则会有编译错误 (js中的各种隐式转换都不用考虑了,开心)
整型
- int 和 int32 在go语言中是两种不同的类型。所以编译器没有办法实现自动类型转换
var value2 int32
value1 :=64 // value1 被编译器默认为int类型
value2 = value1 // 编译错误
value2 = int32(value1)
- 两个不同类型的整数是不能直接比较的,比如int8 和int就不行,但是各种整型变量都可以与字面常量比较
var i int32
var j int64
i,j = 1,2
if i == j {
fmt.println("equal") // 编译报错
}
if i == 1 || j==2 {
fmt.println("equal") // 通过
}
浮点型
- 浮点型包括:float32 和 float64
- 浮点数不是一种精确的表达方式,所以不能用 === 直接哦按段是否相等。这个和那个经典的
0.1 + 0.2 !== 0.3的原理是相似的。替代方案也是类似的, 我们采取截取到某个位数,只要这个位数内的数字是相等的我们就认为这两个数字是相等的。
import "math"
func isEqual(f1,f2, p float64) bool {
return math.Abs(f1-f2) < p
}
字符串
字符串的初始化和声明: var str string str = "hello"
- 字符串的内容可以用数组下标的方式获取,但是是只读的,不能被修改
- 获取字符串长度的函数:
len() - 打印字符串: js中使用的是控制台的console,go需要引入fmt库:
fmt.printlb("hello") - go 只支持utf-8 以及Unicode编码,需要引入go-iconv 等其他的库
- 字符串的链接: a + b
- 字符串的遍历:
- 字节数组的方式遍历
例子会输出的长度为13,因为中文字符在utf-8中占3个字节,而不是1个字节str := "hello,世界" n := len(str) for i:= 0; i < n; i++ { ch := str[i] fmt.println(i,ch) }- unicode字符遍历:
长度为10.每个字符的类型都是runestr := "hello,世界" for i, ch := range str{ ch := str[i] fmt.println(i,ch) }
字符类型
byte代表的字符类型是uint8 的别名,代表utf-8 字符串单个字节的值 rune代表单个unicode字符
数组
js中数组更像一个百宝箱,他什么都能存,什么都能放,没有满的时候,随便添加。但是go就不是了,他指的是同一类型数据的结合。每个元素被叫做数组元素。
元素的读取
for i := 0; i < len(array); i++ {
fmt.println("element:", i , "of array is", array[i])
}
for i, v := range array {
fmt.println(i, v)
}
值类型
在go语言中数组是一种值类型,而js中是引用类型,所以在go中做参数传递的时候都会产生一次复制动作,因此函数体中是无法修改传入的数组的内容。
那我们会想说,我们如果就想修改呢? go语言提供一个更灵活的类型: 数组切片
数组切片
数组切片可以抽象成为三个变量: 一个原声数组的指针,数组切片中的元素个数,数组切片已分配的存储空间
- 创建数组切片
var myArray [10]int = [10] int{1,2,3,4,5,6,7,8,9,10} //数组
var mySlice []int = myArray[:5] // 截取前五个元素的切片。
var mySlice []int = myArray[5: ] //从第5个元素开始的所有元素创建数组切片
- 直接创建
make函数
myslice1 := make([]int, 5) //创建元素个数为5的数组切片
mySlice2 := make([]int, 5, 10) // 创建元素个数为5的数组切片,元素初始值为0,并预留10个元素的存储空间
mySlce3 := []int{1,2,3,4,5} //创建并初始化数组切片
- 元素的遍历
和数组类似,通过len()或者range来遍历
- 动态增加元素
Go中的数组的长度是一定的,前端的小伙伴刚开始可能会不太适应,但是数组切片就和js中的数组很类似了,支持动态的增加删除元素。
数组切片中通过cap()来获取数组切片分配的空间大小,通过len()返回的是数组切片中所存储的元素个数。通俗来讲,就是你的房产证上写的就是cap()的数值,是包括公摊面积的建筑面积,而你实际住的是len的数值,就是使用面积。
如果想增加删除元素的话通过append函数:
mySlice = append(sourceSlice, 1,2,3)
// 第二个参数可以是元素,也可以是另一个切片的扩展
mySlice = append( sourceSlice, anotherSlice...)
这个扩展运算符格外眼熟,但他不是领头羊,而是压轴的。
- 内容复制:
copy(target,source)
slice1 := []int{1,2,3,4,5}
slice2 := []int{5,4,3}
copy(slice2,slice1) // 复制slice1的前三个元素到slice2 ,因为slice2 只有3个位置
map
map在js中是使用object来定义的,go中不需要使用任何库,用起来也很方便。
map的变量声明
var myMap map[string] PersonInfo
map[string]表示的是key的类型为string,personInfo表示值的类型。
map的创建&赋值:make()
myMap = make(map[string] PersonInfo, 100)
myMap ["1234"] = PersonInfo("1","wangxiaomign")
创建一个初始存储能力为100的map。并进行赋值。
元素的删除
delete 函数用于删除容器内的元素:delete(myMap, "1234")
如果1234这个键不存在的话,就什么都不会发生。但是如果传入的map变量的值为nil,则会抛出异常(panic)
元素的查找
通常go语言中获取一个值的常规做法:
- 声明并初始化一个变量为空
- 试图从map中获取相应的键值到该变量中
- 如果变量为空,则不包括这个变量。
因为有的库特别的刚,不存在直接抛出了异常,这可以说是十分暴躁了,导致开发者不得不使用try-catch来包裹。
go中提供了简单可行的方法:(这就是王者)
value,ok := myMap["1234"]
if ok {
// ok
}
结语
今天的文章介绍了go中的基本类型,并简单的和js进行了一些比较,他们之中大部分是不太一样的,可以很明显的看出来强语言类型和弱语言类型的不同。下次会写一下流程控制,以及其他类型方式。
如果本文有什么错误,或者各位观众老爷有什么意见或者建议,都可以在评论区评论。:)
ps: 公司还在招聘,欢迎找我内推~