Fork me on GitHub

Golang之旅27-Golang知识点总结1

标识符

Golang中对各种变量、方法、函数等命名时使用的字符序列,叫做标识符

  1. 命名规则
  • 26个大小写字母,0-9还有_组成
  • 数字不能开头;严格区分大小写
  • 标识符中不能包含空格
  • 不能使用保留关键字(25个)作为标识符;var int int = 30int不是保留关键字,语法通过但是不推荐
  • 下划线本身就是特殊的标识符,称为空标识符,可代表任意其他的标识符,对应的值会被忽略,仅仅是作为占位符使用。
  1. 标识符命名注意事项
  • 包名:包名和目录名保持一致,简短有意义
  • 变量名:采用驼峰体(第一个单词的首字母小写,其余单词的首字母大写)
  • 如果变量名、函数名、常量名的首字母大写,则外部可以访问

KjH6oD.png

保留关键字

总共有25个

Kvi77Q.png

预定标识符

总共36个,包含数据基本类型和系统内嵌函数

Kviqts.png

从终端中获取输入语句

接收用户输入的数据,使用键盘输入语句来获取。

  • 导入fmt
  • 使用fmt包中的fmt.Scanln()、fmt.Scanf()
    • fmt.Scanln():获取一行输入
    • fmt.Scanf():按照指定的format格式输入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
func main(){
var name string
var age byte
var sal float32
var isPass bool

// 1. 使用fmt.Scanln()
fmt.Println("请输入性别 ")
fmt.Scanln(&name) // 引用传递,将地址传过来

fmt.Println("请输入年龄 ")
fmt.Scanln(&age)

fmt.Println("请输入薪水 ")
fmt.Scanln(&sal)

fmt.Println("是否通过考试 ")
fmt.Scanln(&isPass)

fmt.Printf(name, age, sal, isPass)

// 2. 使用fmt.Scanf()
fmt.Println("请输入姓名、年龄、薪水、是否通过考试,使用空格隔开")
fmt.Scanf("%s %d %f %t", &name, &age, &sal, &isPass)
fmt.Printf(name, age, sal, isPass)

}

变量

变量 = 变量名 + 值 + 数据类型

  1. 声明变量

  2. 变量赋值

  3. 使用变量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    package main
    import "fmt"

    // 一次性声明多个变量
    var (
    n1 = 100
    n2 = "xiaoming"
    n3 = 200
    )

    func main(){
    var i int // var i = 10
    i = 10
    i = 30

    var x = 5 // 类型推导方式

    j := 20 // 短变量方式,只能在函数内部声明
    fmt.Println(i, x, j) // i的结果是30,在同一个区域内值可以发生变化,类型不能改变
    fmt.Println(n1, n2, n3)
    }

变量声明三种使用方式

  • 指定变量类型,声明后没有赋值,使用的是默认值(int是0,string是空值)

  • 根据值进行自动推导变量类型

  • 短变量声明

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 多变量声明
    func main(){
    // 声明未赋值,值都是初始值
    var n1, n2, n3 int // 全部是0

    // 声明并赋值
    var n1, name, n2 = 100, "xiaoming", false

    // 短变量声明
    n1, name, n2 := 100, "xiaoming", false
    }

运算符

  1. 算术运算符
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
func main(){
// 取整函数 / 商
fmt.Println(10/4) // 2

var n1 float32 = 10/4
fmt.Printls(n1) // 2

//保留小小数部分
var n2 float32 = 10.0/4
fmt.Printls(n2) // 2.5

// 取模% 余数
// 公式:a % b = a - a / b * b
fmt.Println(10/3) // 1
fmt.Println(-10%3) // -1
fmt.Println(10/-3) // 1
fmt.Println(-10/-3) // -1

// ++ 和 --
var i int = 10
i++ // i = i + 1 = 11
fmt.Println(i)
i-- // i = i - 1 = 10 上面i已经是11
fmt.Println(i)

// 一个单独的语句,只能独立使用,跟在变量之后
// a = i++ 错误写法
// ++i 错误写法

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 练习题

package main()
import "fmt"

func main(){
var days int = 97
var week int = days / 7
var day int = days % 7
fmt.Println("%d个星期0⃣️%d天", week, day)

// 华氏温度转成摄氏温度:5/9(华氏温度-100)
var huashi float32 = 123.3
var sheshi float32 = 5.0 / 9 * (huashi - 100) // 不能写成5/9,这样结果变成了0
fmt.Println("%v 对应的摄氏温度=%v \n", huashi, sheshi)
}
  1. 关系运算符

    • 结果只有falsetrue

    • 主要是用在forif的循环控制中

    • 比较运算符是== 而不是 =

  2. 逻辑运算符

    • 与:$$,短路与
    • 或:||,短路或
    • 非:!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main
import "fmt"

func test(){
fmt.Println("hello....")
return true
}

func main(){
var i int = 10
if i < 9 && test(){ // 因为i<9已经是false,后面的test函数不会执行,所以什么也不输出
fmt.Println("golang")
}

if i > 9 || test(){ // 因为i>9是true,所以后面的test()不执行,只输出"golang"
fmt.Println("golang")
}
}
  1. 赋值运算符

    符号 说明
    = 基本赋值
    += 加之后再赋值
    -= 减之后再赋值
    *= 乘之后再赋值
    /=、%= 取整、求余后再赋值
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // 赋值交换

    func test(){
    return 9
    }

    func main(){
    a := 9 // 定义两个变量
    b := 2
    t := a // 定义一个临时变量t
    a = b // 将b的值赋值给a
    b = t // 将t的值赋值给b

    // 赋值表达式的左边只能是变量,右边可以是变量、常量、表达式、函数等
    var c int
    c = a
    c = 9 + 1
    c = test() + 4
    c = 88
    fmt.Println(c)
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 交换两个变量,不使用中间变量
    func main(){
    var a int = 10
    var b int = 20

    a = a + b // a = 10 + 20;此时a变成30,b不变为20
    b = a - b // b = 30 - 20;此时b变成10,a还是上面的30
    a = a - b // a = 30 - 10;此时a变成20,b还是上面的10
    }
  2. 运算符优先级

    1. 括号,++,–
    2. 单目运算符(右—>左)
    3. 算术运算符
    4. 移位运算符
    5. 关系运算符
    6. 位运算符
    7. 逻辑运算符
    8. 赋值运算符(右—>左)
    9. 逗号

    KvKJiT.png

  3. 进制

    1. 二进制:0-1,满2进1;Golang中不能直接表示二进制
      1. 二进制转成八进制:低位开始,每3位一组11010101=0325
      2. 二进制转成十六进制:低位开始,每4位一组 11010101=0xD5
    2. 十进制:0-9,满10进1
    3. 八进制:0-7,满8进1,数字0开头。八进制转成二进制:每1位分别转成3位的二进制0237=10011111
    4. 十六进制:0-9,A-F,满16进1;以0X或者0x开头。字母不区分大小写。十六进制转成二进制:每位转成4位的二进制0x237=1000110111
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    func main(){

    // 二进制输出
    i := 5
    fmt.Printf("%b \n",i)

    // 八进制
    j := 011 // 9
    fmt.Println(j)

    // 十六进制
    k := 0x11 // 17
    fmt.Println(k)
    }
  4. 位运算符

计算机内部的计算都是通过二进制的方式进行。

  • 按位与&:两个都是1,结果才是1,否则是0
  • 按位或|:只要有一个1,结果为1,否则是0
  • 按位异或^:一个0,一个1,结果才是1,否则是0
  • 左移运算符<<:符号位不变,低位补0
  • 右移运算符>>:低位溢出,符号位不变,并用符号位补充溢出的高位
1
2
3
4
5
6
7
8
9
// 3种位运算
func main(){
fmt.Println(2&3) // 00000010 & 00000011 = 00000010=2
fmt.Println(2|3) // 00000010 | 00000011 = 00000011=3
fmt.Println(2^3) // 00000010 ^ 00000011 = 00000001=1

// 先把-2的补码求出来:1111 1110
fmt.Println(-2^2) // 11111110 ^ 00000010 = 11111100(补码)--->11111011(反码)--->10000100(原码)-4
}
  1. 其他运算符
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// & 取地址和 * 取地址中的值

func main(){
a := 100
fmt.Println("a的地址是", &a)

var ptr *int = &a // 将 a 的地址给指针变量 ptr
fmt.Println("ptr 指向的值是=", *ptr)

// 2个数中的最大值
n1 := 10
n2 := 20
var max int
if n1 > n2{
max = n1
}else{
max = n2
}
fmt.Println("2个数中的最大值", max) // 找到2个数中的最大值

// 3个数中的最大值:先求出2个数中的最大值,再和第3个数进行比较
n3 := 45
if n3 > max{
max = n3
}
fmt.Println("3个数中的最大值:", max)


// golang不支持三元运算符
var n int
i := 10
j := 18
if i > j {
n = i
}else {
n = j
}
fmt.Println(n) // 18
}

9 . 原码、反码、补码

二进制的最高位表示符号位,0表示正数,1表示负数。

  • 正数的原码、反码、补码都是一样的

  • 负数的反码 = 原码符号位不变,其他位取反(0和1取反)

  • 负数的补码=反码 + 1

  • 0的反码和补码都是0

在计算机中的运算都是通过补码的形式来进行的。

数据类型

bit是计算机中的最小存储单位,byte是计算中基本存储单元。byte = 8 * bit

go中默认是整型int

实际中,在保证程序正常运行的情况下,保小不保大,节省空间。

  • 基本数据类型

    • 数值型
      • 整数型:int,int8/16/32/64;uint,uint8/16/32/64(1,2,4,8个字节)
      • 浮点型:float32(4字节),float64(8字节);可能造成精度损失,64位更精确
    • 字符型
      • byte:uint8,存储字符选用byte;无符号(0-255)
      • rune:int32,处理中文,有符号
    • 布尔型bool
    • 字符串string
  • 派生数据类型

    • 指针pointer
    • 数组array
    • 结构体structure
    • 管道Chanel
    • 函数function
    • 切片slice
    • 接口interface
    • 映射map
1
2
3
4
5
6
7
8
9
10
package main
import (
"fmt"
"unsafe"
)

func main(){
var n1 int64
fmt.Printlf("n1 的类型是 %T n1 占用的字节数是 %d", n1, unsafe.Sizeof(n1)) // unsafe.Sizeof() 查看字节数
}

需要注意的地方:

  • 浮点类型可能造成精度损失;float64更加精确
  • 浮点类型有固定的长度和字符类型,不受操作系统的影响
  • Golang中默认的是float64,开发中建议使用
  • 支持科学计数法:5.23e5 = 5.23 * 10的5次方

字符类型

go中没有专门的字符串类型,一般使用byte表示;如果直接输出byte的变量,实际上是输出其对应的ascii码值。go`中字符串是由字节组成的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main
import "fmt"

func main(){
var c1 byte = 'a'
var c2 byte = 'b' // byte范围是0-255

var c3 int = '北' // 超出范围使用int,不能再用byte

var c4 int = 22269 // "国"

var c5 = 10 + 'a' // 107 = 10 + 97
fmt.Println(c1, c2, c3, c4, c5)
}
  • 如果保存的值在255之内,可以使用byte
  • 如果超出255,使用int
  • 字符常量用单引号括起来
  • 使用的是utf-8编码,英文字母是一个字节,汉字是3个字节。
  • 字符的本质是一个整数,直接输出时,就是该字符对应的UTF-8编码
  • 字符类型是可以进行运算的,相当于是整数,对应的是Unicode
  • 存储:字符—>对应码值—>二进制—>存储
  • 读取:二进制—>码值—>字符—>读取

布尔类型

只有两个false true,占用一个字节;主要是用于流程控制

字符串类型

字符串是由一连串的字符连接起来的字符序列,使用的utf-8编码标识的unicode文本。

1
2
3
4
5
6
7
8
9
10
11
package main
import "fmt"

func main(){
var address string = "北京长城 hello golang"
fmt.Println(address)

// 拼接
var str = "hello" + "golang" // 如果比较长,转行时,需要将加号+放在上行末尾
str += " haha!"
}
  • 字符串一旦赋值,就不能被修改
  • 双引号可以识别转义字符
  • 支持使用反引号``,使得字符串以原生的形式输出,包括换行和特殊字符
  • 使用utf-8,解决中文乱码问题

默认值和强制转换

默认值

当数据类型没有被赋值,则使用零值。

  • 整型:0
  • 浮点型:0
  • 字符串:""
  • 布尔型:false
转换

go中是强制类型转换,显式转换,不能自动转换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main
import "fmt"

func main(){
var i int32 = 100
var j float32 = float32(i) // 强制类型转换
var k int8 = int8(i)
fmt.Println(i, j, k) // i还是int32没有变化

var n1 int32 = 12
var n3 int8
var n4 int8
n4 = int8(n1) + 127 // 编译通过,但是结果不是129,发生溢出问题
// n3 = int8(n1) + 128 编译不通过,128超出int8的范围
}
  • 被转换的是变量存储的数据,变量本身的数据类型是没有变化的。
  • 范围大—>范围小,编译不会报错,按照溢出处理

基本数据类型—>string

  1. fmt.Sprintf:生成格式化的字符串,并返回字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
func main(){
var num1 int = 99
var num2 float64 = 23.5455
var b bool = true
var myChar byte = 'h'
var str string // 空的str

// 1. 通过fmt.Sprintf
str = fmt.Sprintf("%d", num1)
fmt.Printf("str type %T str=%q\n", str, str)

str = fmt.Sprintf("%f", num2)
fmt.Printf("str type %T str=%q\n", str, str)

str = fmt.Sprintf("%t", b)
fmt.Printf("str type %T str=%q\n", str, str)

str = fmt.Sprintf("%c", myChar)
fmt.Printf("str type %T str=%q\n", str, str)

// 2. strconv
var num3 int = 99
var num4 float64 = 23.5455
var c bool = true

str = strconv.FormatInt(int64(num3), 10)
fmt.Printf("str type %T str=%q\n", str, str)

// 说明:f是转换格式,10是精度,64:float64位
str = strconv.FormatInt(num4, 'f', 10, 64)
fmt.Printf("str type %T str=%q\n", str, str)

str = strconv.FormatBool(c)
fmt.Printf("str type %T str=%q\n", str, str)

// Itoa函数
var num5 int = 345
str = strconv.Itoa(num5) // 参数必须是int类型,如果不是使用int()函数先转换
fmt.Printf("str type %T str=%q\n", str, str)
}
  1. strconv包中的函数
    • FormatInt
    • FormatBool
    • FormatUint
    • FormatFloat

string—>基本数据类型

使用的是strcon包中的函数;要确保string类型能够转成有效的数据。比如“123”能转成整型,但是“hello”不行,Golang直接转成零值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main
import "fmt"

func main(){
var str string = "true"
var b bool

// 函数有两个值:布尔值和error,关心的是bool
// 下划线 _ 表示忽略
b, _ = strconv.ParseBool(str)
fmt.Printf("b type %T b=%v", b, b)

var str2 string = "1234"
var n1 int64
var n2 int
n1, _ = strconv.ParseInt(str2, 10, 64) // 返回值是64位,所有必须使用64位来接收
n2 = int(n1)
fmt.Printf("n1 type %T n1=%v", n1, n1)
fmt.Printf("n2 type %T n2=%v", n2, n2)

var str3 string = "123.45"
var f1 float64
var f2 float32
f1, _ = strconv.ParseFloat(str3, 64) // float只有32和64两种位数
f2 = float32(f1)
fmt.Printf("f1 type %T f1=%v", f1, f1)
fmt.Printf("f2 type %T f2=%v", f2, f2)
}

指针

  1. 对于基本数据类型,变量存的就是值,也叫做值类型
  2. 获取变量的地址用&,获取地址的值用*
  3. 指针变量存的是地址,地址指向的空间存的才是真正的值var ptr *int = &numptr就是指针。
  4. 值类型都有对应的指针类型,*datatype。int—>*int;float—>*float。值类型包含
    • Int\float
    • bool\string
    • 数组array
    • 结构体struct
1
2
3
4
5
6
7
8
9
10
11
12
13
14
func main(){
// 基本数据类型的布局
var i int = 10
// i的地址:&i
fmt.Println(&i)

// 1. ptr是指针类型变量
// 2. ptr的类型是 *int(指针类型)
// 3. ptr本身的值是&i,即 i 的内存地址
var ptr *int = &i
fmt.Printf("ptr=%v\n", ptr)
fmt.Printf("ptr 的地址=%v", &ptr) // 获取地址
fmt.Printf("ptr 指向的值=%v",*ptr) // 获取地址指向的值
}

KjW4sg.png

1
2
3
4
5
6
7
8
9
10
11
12
// 输出地址
package main
import "fmt"

func main(){
var num int = 9
fmt.Printf("num address=%v", &num) // 获取变量的地址
var ptr *int
ptr = &num
*ptr = 10 // 修改会改变num的值
fmt.Println("num=", num)
}

KjhSc8.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 指针练习

package main
import "fmt"

func main(){
var a int = 300 // 定义两个int变量
var b int = 400
var ptr *int = &a // 指针变量ptr为a的内存地址,值的指向是a
*ptr = 100 // 将ptr指向的值改为100,则 a=100
ptr = &b // ptr变成b的内存地址
*ptr = 200 // 将ptr指向的值修改为200,b=200
fmt.Printf("a=%d b=%d ptr=%d",a,b,*ptr)
}

值类型和引用类型

  1. 值类型:变量直接存储值,内存通常在中进行分配

    • int\float

    • bool\string

    • 数组array

    • 结构体struct

  2. 引用类型:变量存储的是地址,地址的空间才是真正存储的数据(值),内存通常在上进行分配。如果没有任何变量引用这个地址,由GC进行垃圾回收

    • 指针pointer
    • 切片slice
    • 映射map
    • 管道channel
    • 接口interface

KjoVZF.png

本文标题:Golang之旅27-Golang知识点总结1

发布时间:2019年11月04日 - 13:11

原始链接:http://www.renpeter.cn/2019/11/04/Golang%E4%B9%8B%E6%97%8527-Golang%E7%9F%A5%E8%AF%86%E7%82%B9%E6%80%BB%E7%BB%931.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

Coffee or Tea