go-basic-learning-week01
✨你好啊,我是“ 罗师傅”,是一名程序猿哦。
🌍主页链接:楚门的世界 - 一个热爱学习和运动的程序猿
☀️博文主更方向为:一起来学go(狗)语言。随着专业的深入会越来越广哦…一起期待。
❤️一个“不想让我曾没有做好的也成为你的遗憾”的博主。
💪很高兴与你相遇,一起加油!
前言
江湖儿女们,听我一言!自我初识Java以来,侠者心中燃起一抹热忱,追求编程的精髓。然而,多年的江湖岁月让我领悟到一种新的力量——Go语言。
🌟🌟🌟基础语法
👻👻变量和常量
🍱变量定义
使用Var关键字
- var a, b, c bool
- var s1, s2 string = “hello”, “world”
- 可以放在函数内,或直接放在包内
- 使用var()集中定义变量
让编译器自动决定类型
- var a, b, i, s1, s2 = true, flase, 3, “hello”, “world”
使用:=定义变量
- a, b, i, s1, s2 := true, flase, 3, “hello”, “world”
- 只能在函数内使用
🍘内建变量类型
- bool, string
- (u)int, (u)int8, (u)int16, (u)int32, (u)int64, uintptr
- byte, rune
- float32, float64, complex64, complex128
🍙强制类型转换
🍛常量定义
- const filename = “abc.txt”
- const数值可作为各种类型使用
- const a, b = 3, 4
一次声明多个常量
1
2
3
4
5
6 const (
name = "lwsj"
age = 21
flag = true
price = 12.23
)
🥡使用常量定义枚举类型
- 普通枚举类型
1
2
3
4
5
6 const (
cpp = 0
java = 1
python = 2
golang = 3
)
- 自增枚举类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 const (
cpp = iota // 自动递增
java
python
golang
)
// b, kb, mb, gb, tb, pb
const (
b = 1 << (10 * iota)
kb
mb
gb
tb
pb
)
// 1 1024 1048576 1073741824 1099511627776 1125899906842624
🏌变量定义要点回顾
- 变量类型写在变量名之后
- 编译器可推测变量类型
- 咩有char,只有rune
- 原生支持复数类型
💦💦条件语句
🦸♂if
1
2
3
4
5 if contents, err := ioutil.ReadFile(filename); err == nil {
fmt.Println(string(contents))
} else {
fmt.Println("cannot print file contents:", err)
}
- if的条件里可以赋值
- if的条件里赋值的变量作用域就在这个if语句里
🤔switch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 func eval(a, b int, op string) int {
var result int
switch op {
case "+":
result = a + b
case "-":
result = a - b
case "*":
result = a * b
case "/":
result = a / b
default:
panic("unsupported operation: " + op)
}
return result
}
- switch后可以没有表达式
- switch会自动break,除非使用fallthrough
🫡🫡循环
🐋for
1
2
3
4
5
6
7
8
9
10
11
12
13
14 sum := 0
for i := 1; i <= 100; i++ {
sum += i
}
for { // 死循环
fmt.Println("abc")
}
// 转二进制
for ; n > 0; n /= 2 { // 省略初始条件,相当于while
lsb := n % 2
result = strconv.Itoa(lsb) + result
}
- for的条件里不需要括号
- for的条件里可以省略初始条件,结束条件,递增表达式
- 省略初始条件,相当于while
🐙基本语法要点回顾
- for, if 后面的条件没有括号
- if条件里也可以定义变量
- 咩有while
- switch不需要break,也可以直接switch多个条件
🍭函数
1
2
3 >func div(a, b int) (q, r int) {
return a / b, a % b
>}
- 返回值类型写在最后面
- 函数可以返回多个值
- 函数返回多个值时可以起名字(建议仅用于非常简单的函数)
- 没有默认参数,可选参数(只有可变参数 (int…))
- 函数可以作为参数使用
🧋指针
1
2
3
4 var a int = 2
var pa *int = &a
*pa = 3
fmt.Println(a)
- Go的指针不能运算
- Go语言只有值传递一种方式
🎊🎊🎊内建容器
🌳🌳数组
1
2
3
4
5
6
7
8
9
10
11 // 数组的定义
var arr1 [5]int
arr2 := [3]int{1, 2, 3}
arr3 := [...]int{2, 4, 6, 8, 10}
var grid [4][5]int
// 数组的遍历
sum := 0
//for i, v := range numbers {
for _, v := range numbers {
sum += v
}
- 可以通过 _ 省略变量(当我不想使用该变量的时候)
- 不仅range,任何地方都可以通过 _ 省略变量
🌵为什么要使用range呢?
- 意义明确,美观
- c++: 没有类似能力
- Java/Python:只能for each value, 不能同时获取 i, v
🌲数组是值类型
- [10]int和[20]int是不同类型
- 调用func f(arr [10]int) 会拷贝数组
- 在go语言中一般不直接使用数组(而是用切片)
🍀🍀Slice(切片)
1
2
3
4
5 arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
s := arr[2:6] // s的值为[2,3,4,5] 左闭右开
s[0] = 10 // arr的值变为[0,1,10,3,4,5,6,7]
s1 := arr[2:6] // [2,3,4,5]
s2 := s1[3:5] // [5,6]
- slice本是没有数据,是对底层array的一个view
- slice 可以向后扩展,不可以想前扩展
- s[i]不可以超越len(s),向后扩展不可以超越底层数组cap(s)
🌍向Slice添加元素
- 添加元素时如果超越cap,系统会重新分配更大的底层数组
- 由于是值传递的关系,必须接收append的返回值
- s = append(s, val)
🌞🌞Map
1
2
3
4
5
6 m := map[string]string{
"name": "ccmouse",
"course": "golang",
"site": "imooc"
"quality": "notbad",
}
- map[K]V, map[K1]map[K2]V
Map的操作
- 创建:make(map[string]int)
- 获取元素:m[key]
- key不存在时,获得Value类型的初始值
- 用value, ok:=m[key]来判断是否存在key
- 用delete删除一个key
Map的遍历
- 使用range遍历key,或者遍历key, value对
- 不保证遍历顺序,如需顺序,需手动对key排序
Map的key可以是哪些?
- map使用哈希表,必须可是比较相等
- 除了slice,map,function的内建类型都可以作为key
- Struct类型不包含上述字段,也可作为key
🍠🍠rune
1
2
3
4
5
6
7
8
9
10
11
12
13 // rune相当于是go的char
for i, ch := range s { // ch is a rune = int32
fmt.Printf("(%d %X) ", i, ch)
}
// 获得字符数量
fmt.Println(utf8.RuneCountInString(s))
bytes := []byte(s) // []byte获得字节
for len(bytes) > 0 { // len获得字节长度
ch, size := utf8.DecodeRune(bytes) // ch is a rune = int32
bytes = bytes[size:]
fmt.Printf("%c ", ch)
}
- 使用range遍历pos,rune对
- 使用utf8.RuneCountInString获得字符数量
- 使用len获得字节长度
- 使用[]byte获得字节
🔥🔥🔥面向对象
- go语言仅支持封装,不支持继承和多态,更多的组合的形式
- go语言没有class,只有struct
❤️❤️结构体
1
2
3
4 type TreeNode struct {
value int
left, right *Node
}
💕结构的创建
1
2
3
4 func createNode(value int) *TreeNode {
return &TreeNode{value: value}
}
root.left.right = createNode(2)
- 使用自定义工厂函数(相当于是构造函数)
- 注意返回了局部变量的地址
💜为结构定义方法
1
2
3 func (node TreeNode) print() {
fmt.Println(node.value)
}
- 显示定义和命名方法接收者(表示只有TreeNode类型的变量才能使用print方法)
🍅使用指针作为方法接收者
1
2
3
4
5
6
7 func (node *TreeNode) setValue(value int) {
if node == nil {
fmt.Println("Setting Value to nil node. Ignored.")
return
}
node.value = value
}
- 只有使用指针才可以改变结构内容
- nil指针也可以调用方法(所以要判断node == nil)
✌值接收者 vs 指针接收者
- 要改变内容必须使用指针接收者
- 结构过大也考虑使用指针接收者
- 一致性:如有指针接收者,最好都是指针接收者
- 值接收者是go语言特有的
- 值接收者可以接收“值/指针”,但是指针接收者只能接受指针
💪💪封装
- 名字一般使用CamelCase(驼峰命名)
- 首字母大写:public
- 首字母小写:private
📢包
- 每个目录一个包
- main包包含可执行入口
- 为结构定义的方法必须放在同一个包内
- 可以是不同文件
如何扩充系统类型或者别人的类型
- 定义别名: 最简单
- 使用组合:最常用
- 使用内嵌:需要省下许多代码
📣📣📣go语言的依赖管理
- 依赖的概念:就是用别人写好的库
- 依赖管理的三个阶段:GOPATH, GOVENDOR, go mod(好用)
GOVENDOR
- 每个项目有自己的vendor目录,存放第三方库
- 大量第三方依赖管理工具:glide,dep,go dep, …
go mod
- 由go命令统一的管理,用户不必关心目录结构
- 初始化:go mod init
- 增加依赖:go get 或者 go get -u
- 更新依赖:go get[@v…], go mod tidy
- 将旧项目迁移到go mod: go mod init, go build ./…
每一个package main 都应该有自己的包
❤️❤️❤️忙碌的敲代码也不要忘了浪漫鸭!
🍉🍉🍉第一周golang的基础学习到这里就结束啦,这只是go语言的开始,期待下周的学习,我们下周见 拜拜咯~~💪。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 楚门的世界!
评论