第一篇:go之基本类型与函数使用
go之基本类型与函数使用
一、go语言介绍
1 go语言介绍
Go 即Golang,是Google公司2009年11月正式对外公开的一门编程语言,特点:语法简单,速度快。
Go是静态(编译型)强类型语言,是区别于解析型语言的弱类型语言(静态:类型固定 强类型:不同类型不允许直接运算)。
python动态强类型语言。
编译型语言:Java,c,c++,c#,go
解释性语言:python,js,php...
编译型语言涉及到跨平台问题,因为它需要编译成该平台的可执行文件。比如:java运行在jvm之上。go语言可以进行跨平台编译,即交叉编译。比如,从windows上编译成linux上的可执行文件。
解释性不涉及跨平台问题,因为各个平台有各个平台的解释器。
2 go语言特性
- 跨平台的编译型语言,交叉编译
- 管道(channel),切片(slice),并发(routine)
- 有垃圾回收的机制
- 支持面向对象和面向过程的编程模式(go的面向对象中没有类的概念,python是完全的面向对象)
3 go的历史发展
- 2009年11月7日 weekly.2009-11-06 —— 早期的版本
- 2015年8月19日 go1.5 —— 实现的架构变化,同时保留了和旧版本的兼容性,本次更新中移除了”最后残余的C代码”。(从此以后,自举,自己写自己)
- 2018年8月24日 go 1.11 :增加了modules,包管理
- 2020 年 8 月 go 1.15
4 go语言的应用领域
Google、Facebook、腾讯、七牛云
go语言书写:docker、k8s、蓝鲸...
应用领域:服务开发、并发、分布式、微服务等方向。
二、go语言开发环境
1 go环境配置
- IDE(Goland): 集成开发环境。
- 开发环境:sdk【一路下一步即可】
- go语言不需要手动添加到环境变量(python、java需要)
go version
: 打印go的版本信息
注意事项:
-
goland创建项目:需要选择go sdk的安装路径【默认被选中】。
-
指定gopath:代码必须放到该路径下,否则无法执行。【默认会在环境变量中创建GOPATH,需要手动自定义进行修改】。同时,所有的go代码必须放在这个路径下的src文件夹下,否则无法执行【E:\Go_project\src\项目名】。
-
路径和文件都不要出现中文。
2 go常用命令
go version // 查看go的版本信息
go env // 查看go的环境变量
- GO111MODULE=on // 使用了go.mod模式
- GOPATH=E:\Go_project // 代码存放路径
- GOROOT=D:\golang // go sdk安装路径
- ...
go build // 编译。编译型语言,需要先编译再执行,编译成可执行文件
- go build -o name // 指定编译的名字
go run // 编译并执行。两步并作一步
go clean // 清除编译后的可执行文件
go fmt // 格式化代码【没用】
go get // 下载并安装包和依赖等同于pip install
...
三、第一个hello world
//单行注释
/*多行注释*/
编译型语言:
- 编译: go build .\test01.go
- 执行: .\test01.exe
- 编译并执行: go run .\test01.go
编译文件
windows:
- 单个文件:
go build 文件名.go
- 多文件:
go build [-o xx.exe]
linux:
单/多文件:go build *.go
直接运行文件
单个文件:
go run 文件名.go
多文件:
方式一:
编译之后,运行编译的文件
方式二:
直接运行项目名:go run E:\vscoding\gotest\
package main // 声明包名,包名是main
import "fmt" // 内置包
// 定义了一个main函数,go项目运行的入口【所以编译型语言必须有一个入口】
func main() {
fmt.Println("hello world") // 等同于python中的print(python中的print是内置函数)
}
注意:每个go文件都要有一个包名,代表其属于某个包。
goland中文件执行有file、package等几种方式。【可以自己进行配置,一般一个项目中使用package即可,测试的时候使用file就行】
四 变量
1 变量定义
-
var 变量名 变量类型 = 变量值
var age int = 10
go中变量定义了就必须使用,如果不适用就报错。
-
var 变量名 = 变量值
类型推导(可以不写类型)var age = 10
package main import "fmt" // 内置包 func main() { var age int = 10 var name string = "YangYi" fmt.Printf("%T\n", age) // int (看类型,没有python中的type方法,没有自动换行,需要手动\n) fmt.Printf("%T\n", name) // string fmt.Print() // 打印不换行 fmt.Println() // 打印换行 fmt.Printf("%T\n", name) // 查看类型 fmt.Printf("%p", &name) // 0xc0000881e0 }
go中变量类型一旦定义,后期不能改变。(编译型语言通用,python中可以修改,python中存放的内存地址,所以可以改变类型)
-
变量名 := 变量值
简略声明(类型和var关键字都不写)a := 10
a := 10 var a int = 100 var a = 99 // 重复定义,报错(变量不可以重复定义,同时,变量必须先定义,后使用)
/* 只定义,不赋值 */ var a int // 可以(只能用这种方式) var a // 不可以(因为没有类型,不知道a是什么,因为类型需要在定义阶段确定,且不能改)
/* 声明多个变量 */
var width, height int = 100, 50 // 第一种
var width, height = 100, 50 // 第二种
width, height := 100, 50 // 第三种
var (
name = "YangYi" // 不赋类型
age int = 29 // 赋类型
height int // 声明
)
/* 小坑 */
var a int =10
// var b =99
b,a:=99,100 //这个不报错,我们觉得是重复定义,冒号左侧,只要有一个没有定义过的变量,就可以
2 变量定义规范
2.1 变量命名规范
变量命令建议用驼峰(大小写有特殊意义【私有和公有的意义】);
go文件命名建议用 下划线;(ps:python中都建议都使用下划线;java中建议都是驼峰;js中变量名驼峰)
一个名字必须以一个字母(Unicode字母)或下划线开头,后面可以跟任意数量的字母、数字或下划线;
大写字母和小写字母是不同的:Name和name是两个不同的变量;
关键字和保留字都不建议用作变量名;
2.2 go语言中的关键字
// Go语言中关键字有25个
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
// Go语言中保留字有37个,主要对应内建的常量、类型和函数
内建常量: true false iota nil
内建类型: int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
float32 float64 complex128 complex64
bool byte rune string error
内建函数: make len cap new append copy close delete
complex real imag
panic recover
五 数据类型
1 基础数据类型
-
数字
// 有符号整形 int //在32位机器是int32,在64位机器是int64 int8 // 表示整数范围是:8个比特位,8个bit是1byte ,负数和0, 2的7次方-1 的范围 int16 // 2的15次方减一 int32 int64 /* 强类型举例: var a int8 = 10 var b int16 = 20 fmt.Println(a + b) // 报错【go是强类型,其中没有java中的自动类型转换一说】 fmt.Println(int16(a) + b) */ /* byte:是int8的别名 单引号包裹 rune:是int32的别名 单引号包裹 */ var a byte = 99 // int8 fmt.Println(a) var b byte = 'b' // 存放的是字符,其中也是数字而已 fmt.Println(b) // 98 var c rune = '你' // 可以打印,字符中其实是数字 fmt.Println(c) // 20320 var d byte = '你' fmt.Println(d) // 报错,超出范围 // 无符号整形 uint8 2的8次方减一 (定义一个人的年龄) uint16 uint32 uint64 // 浮点数(小数),表示小数点后长度多少位 float32 float64 // 复数 complex64 complex128 var a complex64 = 20 + 10i
-
字符串
"双引号包裹" `反引号包裹` // 和js一样; python中是 """ """
-
布尔类型
bool //true 和 false var flag bool = false var flag = true
数据类型默认值:数字类型是0, 字符串类型是空字符串,布尔类型是false。
java | go |
---|---|
byte | int8 |
short | int16 |
int | int32 |
long | int64 |
float | float32 |
double | float64 |
2 常量
go中常量定义使用const
关键字;java中的常量为final
关键字;python中是大写
。
-
const 变量名 变量类型 = 变量值
const name string = "yangyi" // 常量可以定义之后不使用,不会报错
-
const 变量名 = 变量值
const age = 90
-
其他定义方式
const name, age = "yangyi", 18 const ( name string = "yangyi" age = 18 ) // 应该不会使用吧 const ( s1 = iota s2 s3 = iota s4 = 99 s5 ) fmt.Println(s1) // 0 fmt.Println(s2) // 1 fmt.Println(s3) // 2 fmt.Println(s4) // 99 fmt.Println(s5) // 99 太奇怪 const ( s1 = iota s2 s3 = iota s4 = 99 s5 = iota ) fmt.Println(s1) // 0 fmt.Println(s2) // 1 fmt.Println(s3) // 2 fmt.Println(s4) // 99 fmt.Println(s5) // 4 太奇怪
六 函数
1 函数基础
func 函数名(参数名 类型, 参数名 类型)(返回值类型, 返回值类型){
函数体内容
return 返回值1, 返回值2
}
函数使用示例
// 1 有参数无返回值
func add(a int, b int){
fmt.Println(a + b)
}
add(100, 200) // 调用函数
// 2 有参数无返回值,有多个相同类型的参数
func add(a, b int){
fmt.Println(a + b)
}
// 3 有参数无返回值,有多个不同类型的参数
func add(a, b int, msg,name string){
}
// 4 多个参数,一个返回值
func add(a, b int) int {
return a + b
}
// 5 多个参数,多个返回值【python和go支持多返回值】
func add (a, b int) (int, int){
return a + b, a * b
}
a, b := add(100, 200) // 多返回值就需要用多变量进行接受【和python一样】
a, _ := add(3, 4) // python中的下划线可以打印,但是go中就是空
// 6 命令返回值
func add(a, b int) (c int, d int){
c = a + b // 就是在函数体中已经声明了c d的变量
d = a * b
return // 就会直接将c d返回出去,不需要写 return c,d
}
2 函数高级
函数是一等公民,函数可以赋值给变量【python中也是如此】
在编译型语言中,和解释性语言不同,没有先定义函数,后使用函数一说,编译之后都能找到。
// 匿名函数(定义在函数内部,不能有名字): python中是lamdba
// 第一种
func (){
}() // 匿名函数直接调用
// 第二种
var a func() // 定义一个变量,类型为func()【哈哈】
a = func(){ // 此时a是一个函数
fmt.Println("我是匿名函数")
}
a() // 我是匿名函数
// 7 函数返回值为函数
func test() func(){
return func(){
fmt.Println("我是返回的函数...")
}
}
a := test()
fmt.Println(a) // 0x5451e0 【打印函数名,拿到的还是函数的内存地址】
// 8 返回值函数,返回的函数带参数
// 返回值类型必须跟返回的函数类型匹配 即 func()和func(msg string)不是一个类型
func test() func(msg string){ // 返回值类型必须跟返回的函数类型匹配
return func(msg string){
fmt.Println("我是返回的函数...")
}
}
a := test()
a("hello") // 函数调用
// 9 函数返回值为函数,返回的函数带参数,带返回值
func test() func(a, b int) int {
return func(a, b int) int {
return a + b
}
}
a := test() // a的类型为 var a func(a, b int)int
fmt.Println(a(2, 3))
// 10 函数参数为函数类型,返回值为带参数带返回值的函数类型
func test(f func()) func(a, b int) (int, int){
f() // f函数执行
return func(a, b int) (int, int){
f() // f函数执行
return a + b, a * b
}
}
// 函数操作
a, b := test(
func(){
fmt.Println("我是函数参数...")
},
)(3, 4) // 函数调用
// 或者
f := func(){
fmt.Println("我是函数参数...")
}
f1 := test(f)
a, b := f1(3, 4)
fmt.Println(a, b)
3 闭包函数
①定义在函数内部; ②对外部作用域有引用; 【可以实现C++函数中的static关键字功能】
闭包函数其实就是多了一种对函数传参的方式。
func test(age int) func() {
// age := 18
a := func(){ // 定义在函数内部
fmt.Println(age) // 对外部作用域有引用
}
return a
}
a := test(19)
a() // 闭包函数的调用【并没有传参,实际上已经有参数传递进去】
// 一般来说,函数执行完毕,参数应该被释放,但是由于闭包函数的存在,所以age一直没有被释放,有东西对其有引用。【引出内存逃逸: 正常应该被回收,其实没有被回收】
// 装饰器是闭包函数的典型应用(go语言中没有装饰器的语法糖,python中有语法糖)
4 type类型重命名
type MyFunc func() // 类型重命名
func test() MyFunc {
return func(){
}
}
type MyFunc func(a,b int)(int,string)
func test() MyFunc {
return func(a,b int)(int,string) {
fmt.Println("xxx")
return 10,"ok"
}
}
type Myint int // 这里Myint和int已经不是一个类型了
var a int = 10
var b Myint = 100
fmt.Println(a + b) // 报错
fmt.Println(a + int(b)) // 强制类型转换
5 变量的作用域范围
同一个包下,函数名不能重名。比如:都在main包中
// 第一种方式
var a int //全局变量,全局有效,只要改了,就是改了【python修改全局变量,需要添加global】
func main() {
fmt.Println(a) //0
a=19
fmt.Println(a) //19
test1() //99
fmt.Println(a) //99
}
func test1() {
a=99
fmt.Println(a) // 99
}
// 第二种方式【局部 ——> 全局 ——> 内置】
var a int //全局变量,全局有效,只要改了,就是改了
func main() {
var a int
fmt.Println(a) //0
a = 19
fmt.Println(a) //19
test1() // 0
fmt.Println(a) //19
}
func test1() {
fmt.Println(a)
}