Go基本数据类型
第一部分:基本数据类型和操作符
1. 文件名&关键字&标识符
1. 所有go源码以.go结尾
2. 标识符以字母或下划线开头,大小写敏感,比如:
a. boy b. Boy c. a+b d. 0boy e. _boy f. =_boy g. _
3. _是特殊标识符,用来忽略结果
4. 保留关键字
break default func interface select case defer go map struct chan else goto package switch const fallthough if range type continue for import return var
3. 常量和变量
4. 数据类型和操作符
5. 字符串类型
go程序的基本结构
package main import “fmt” func main() { fmt.Println(“hello, world”) }
运行:
go run hello.go
1. 任何一个代码文件隶属于一个包
2. import 关键字,引用其他包:
import(“fmt”) import(“os”)
通常习惯写成: import ( “fmt” “os” )
3. golang可执行程序,package main,并且有且只有一个main入口函数
4. 包中函数调用:
a. 同一个包中函数,直接调用
b. 不同包中函数,通过包名+点+函数名进行调用
5. 包访问控制规则:
a. 大写意味着这个函数/变量是可导出的
b. 小写意味着这个函数/变量是私有的,包外部不能访问
包的概念
练习
方式一:
main.go
package main import ( "fmt" "go_dev/day2/example1/add" ) func main() { fmt.Println("Name:", add.Name) fmt.Println("Age:", add.Age) }
add.go
package add // 可以这么声明赋值,在编译前就确定值了 var Name string = "hbw" var Age int = 18
方式二:
main.go
package main import ( "fmt" "go_dev/day2/example1/add" ) func main() { add.Test() fmt.Println("Name:", add.Name) fmt.Println("Age:", add.Age) }
add.go
package add var Name string // 默认 "" var Age int // 默认 1 // 不能这么赋值,编译会出错 // Name = "hbw" // Age = 18 // 要有入口函数,才能初始化值 // 执行语句不能独立与函数之外 func Test() { Name = "hbw" Age = 18 }
包取别名
4. 每个源文件都可以包含一个init函数,这个init函数在main函数执行前自动被go运行框架调用。开发一个程序演示这个功能?
执行顺序:先全局变量 --> init --> main
main.go
package main import ( "fmt" "go_dev/day2/example1/add" ) // add的init函数在main执行前执行,就获得了add.Name,add.Age的值 func main() { fmt.Println("Name:", add.Name) fmt.Println("Age:", add.Age) }
add.go
package add var Name string // 默认 "" var Age int // 默认 1 func init() { Name = "hbw" Age = 18 }
5. 包的只初始化,不引用。请开发一个程序,演示这个做法
package main import( _ “add” ) func main () { fmt.Println(“add not refer:”) }
函数声明和注释
1. 函数声明: func 函数名字 (参数列表) (返回值列表){}
2. 注释,两种注释,单行注释: // 和多行注释 /* */
常量
1. 常量使用const 修饰,代表永远是只读的,不能修改。
2. const 只能修饰boolean,number(int相关类型、浮点类型、complex)和string。
3. 语法:const identifier [type] = value,其中type可以省略。
4. 比较优雅的写法:
const ( a = 0 b = 1 c = 2 )
5. 更加专业的写法:
iota讲解:
https://studygolang.com/articles/2192
// iota: a为0,下面的变量自增1 const ( a = iota b //1 c //2 )
变量
1. 语法:var identifier type
package main import ( “fmt” “os” ) func main() { var goos string = os.Getenv(“GOOS”) fmt.Printf(“The operating system is: %s ”, goos) path := os.Getenv(“PATH”) fmt.Printf(“Path is %s ”, path) }
值类型和引用类型
1. 值类型:变量直接存储值,内存通常在栈中分配。
2. 引用类型:变量存储的是一个地址,这个地址存储最终的值。内存通常在堆上分配。通过GC回收。
1. 值类型:基本数据类型int、float、bool、string以及数组和struct。
把值类型传入函数改变它的值,外面的值不会变
2. 引用类型:指针、slice、map、chan等都是引用类型。
把引用类型传入函数改变它的值,外面的值也会变
9. 写一个程序,交换两个整数的值。比如: a=3; b=4; 交换之后:a=4;b=3
package main import ( "fmt" ) // *a = 100 是内存地址里的值 func swap(a *int,b *int) { fmt.Println("a: ", a, *a,"b: ", b, *b) tmp := *a *a=*b *b=tmp } func main(){ first:=100 second:=200 swap(&first,&second) // &first 传的是内存地址0xc042068058 fmt.Print(first,second) }
方式二:
package main import ( "fmt" ) func main() { a:=100 b:=200 a,b = b,a fmt.Print(a,b) }
变量的作用域
1. 在函数内部声明的变量叫做局部变量,生命周期仅限于函数内部。
2. 在函数外部声明的变量叫做全局变量,生命周期作用于整个包,如果是大写的,则作用于整个程序。
注意:
a := 100 // 不能在全局使用,编译会报错 // 因为它是两条语句,全局只能声明变量,不能执行代码 a := 100 等价 var a int a = 100 // 是赋值语句,只能在函数里执行,全局它就会报错
数据类型和操作符
1. bool类型,只能存true和false
var a bool var a bool = true var a = true
2. 相关操作符, !、&&、||
var a bool = true var b bool // 默认false 请问!a 、!b、a && b、a || b的值分别是多少?
a && b 与
短路特性
前面是false,它就不会求后面的表达式了
a || b 或
短路特性
前面是true,它就不会求后面的表达式了
3. 数字类型,主要有int、int8、int16、int32、int64、uint8、uint16、uint32、uint64、float32、float64
uint无符号类型 符号占一位
4. 类型转换,type(variable),比如:var a int=8; var b int32=int32(a)
package main func main() { var a int var b int32 a = 15 b = a + a // compiler error b = b + 5 // ok: 5 is a constant }
13. 请指出下面程序的输出是什么?
package main import “fmt” func main() { var n int16 = 34 var m int32 m = n // 编译报错 m = int32(n) // Printf 格式化输出 fmt.Printf(“32 bit int is: %d ”, m) fmt.Printf(“16 bit int is: %d ”, n) }
1. 逻辑操作符: == 、!=、<、<=、>和 >=
2. 数学操作符:+、-、*、/等等
package main Import ”fmt” func main() { var a int = 10 var b = a + 10 }
5. 字符类型:var a byte
var a byte = ‘c’
6. 字符串类型: var str string
package main import “fmt” func main() { var str = “hello world” fmt.Println(“str=“, str) }
1. 字符串表示两种方式: 1)双引号 2)`` (反引号)
package main import "fmt" func main() { var str = "hello world " // 反引号原样输出 var str2 = `hello this is a test string This is a test string too·` fmt.Println("str=", str) fmt.Println("str2=", str2) }
var b byte = 'c' 输出的是asscii表的数字和Java一样
服务器负载均衡
大型互联网公司负载均衡使用的是自己写的rpc库,实现负载均衡,健康检查
用rpc好处 rpc和web在一个进程里面rpc只是个库,这样我们就没有一个集中式的东西
LVS有个集中式的,流量都通过LVS去转发,但通过LVS转发可能有问题,LVS到了性能瓶颈,扛不住了,那所有通过LVS去转发的服务都会受影响
通过rpc去调,就不会通过集中式的中间节点,不会有断点的问题
有中间节点的话,中间节点(LVS)挂了,后面所有的等于就挂了
后面的服务器挂了一台,它会被rpc剔除,类似nginx upstream模块