目录
go
Go是2009年开源的编程语言,Go语言具有以下特性:语法简洁、并发编程、编译迅速、数组安全、丰富的内置类型、错误处理、匿名函数和闭包、反射、函数多返回值、自动垃圾回收
Go语言最初由Google公司的Robert Griesemer、Ken Thompson和Rob Pike三个大牛于2007年开始设计发明,他们最终的目标是设计一种适应网络和多核时代的C语言。所以Go语言很多时候被描述为“类C语言”,或者是“21世纪的C语言”,当然从各种角度看,Go语言确实是从C语言继承了相似的表达式语法、控制流结构、基础数据类型、调用参数传值、指针等诸多编程思想。但是Go语言更是对C语言最彻底的一次扬弃,它舍弃了C语言中灵活但是危险的指针运算,还重新设计了C语言中部分不太合理运算符的优先级,并在很多细微的地方都做了必要的打磨和改变。
go与C语言区别
-
包声明(自说明),编写源文件时,必须在非注释的第一行指明这个文件属于哪个包,如package main。
-
引入包(头文件),其实就是告诉Go 编译器这个程序需要使用的包,如import "fmt"其实就是引入了fmt包。
-
函数,和c语言相同,即是一个可以实现某一个功能的函数体,每一个可执行程序中必须拥有一个main函数。
-
变量,Go 语言变量名由字母、数字、下划线组成,其中首个字符不能为数字。
-
语句/表达式,在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号 ; 结尾,因为这些工作都将由 Go 编译器自动完成。
-
注释,和c语言中的注释方式相同,可以在任何地方使用以 // 开头的单行注释。以 /* 开头,并以 */ 结尾来进行多行注释,且不可以嵌套使用,多行注释一般用于包的文档描述或注释成块的代码片段。
需要注意的是:标识符是用来命名变量、类型等程序实体。一个标识符实际上就是一个或是多个字母和数字、下划线_组成的序列,但是第一个字符必须是字母或下划线而不能是数字。
当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);
标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 protected)。
helloworld
package main
import "fmt"
func main(){
fmt.Println("hello world!")
}
程序执行
go build main.go ---> 生成二进制可执行文件
go run main.go ---> 可直接执行
数据类型
在 Go 编程语言中,数据类型用于声明函数和变量。
数据类型的出现是为了把数据分成所需内存大小不同的数据,编程的时候需要用大数据的时候才需要申请大内存,就可以充分利用内存。具体分类如下:
类型 | 解释 |
---|---|
布尔型 | 布尔型的值只可以是常量 true 或者 false |
数字类型 | 整型 int 和浮点型 float。Go 语言支持整型和浮点型数字,并且支持复数,其中位的运算采用补码 |
字符串类型 | 字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本 |
派生类型 | 指针类型(Pointer)、 数组类型、结构化类型(struct)、Channel类型、函数类型、切片类型、接口类型、Map 类型 |
变量
定义
定义变量格式为
var varname typename
如:定义一个int类型变量
package main
import "fmt"
func main() {
var a int = 27
fmt.Println(a)
}
若变量未进行显式初始化,则为其赋值为空或者0值
-
数值类型(包括complex64/128)为0
-
布尔类型为 false
-
字符串为 “”
-
以下几种类型零值为nil:
var a *int var a []int var a map[string] int var a chan int var a func(string) int var a error // error 是接口
类型推导
即进行显式初始化时,可省略变量类型,由编译器判断
var boolvar = true
简短声明 :=
可省去
var typename
的类型推导,但必须声明并初始化格式
varname := something
,如
a := 1
也可以同时初始化多个变量
a, b, c := 1, 2, 3
此用法比之前定义变量更加方便快捷,但有所限制
-
它只能用在函数内部;在函数外部使用则会无法编译通过,所以一般用
var
方式来定义全局变量
var ( s1 int = 1 s2 bool = true )
-
必须声明并初始化,即:=左侧的varname队列必须有未声明过的变量
func main() {// 即:=左侧只要有未声明的变量就可以使用 var a int = 2 a, b := 1, "123" }
匿名变量
用于占位
匿名变量是一个下画线_,这本身就是一个特殊的标识符,被称为空白标识符。它可以像其他标识符那样用于变量的声明或赋值(任何类型都可以赋值给它),但任何赋给这个标识符的值都将被抛弃,因此这些值不能在后续的代码中使用,也不可以使用这个标识符作为变量对其它变量进行赋值或运算。
使用匿名变量时,只需要在变量声明的地方使用下画线替换即可。
匿名变量不占用内存空间,不会分配内存。匿名变量与匿名变量之间也不会因为多次声明而无法使用
a, b, _ := 1, "123", 2
常量
常量是在程序运行时不会被修改的量。常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型
格式:
const variable [type] = value
const c, d = 3, "4"
编译时函数使用
可使用内置函数初始化,其在编译时计算
常量可以用len()等内置函数计算表达式的值,在常量表达式中,函数必须是内置函数,否则编译不通过
func main() {
const (
a = "123"
b = len(a)
)
fmt.Println(a, b)
}
//123 3
iota
iota为批常量计数(即为一批常量赋值时的计数)
iota是一种特殊常量,可以认为是一个可以被编译器修改的常量。iota在const关键字出现时将被重置为0,const中每新增一行常量声明,iota计数一次。
在批赋值中途,插入新的变量类型,不影响iota的计数
const (
a, b = iota, iota //iota = 0
c, d //iota = 1
e, f = "1", "2" //iota = 2
g, h = iota, iota //iota = 3
)
fmt.Println(a, c, d, e, f, g, h)
//输出 0 1 1 1 2 3 3 0 1
并且,常量的类型推导,是根据赋值来确定的,如果未进行赋值,则以前一行所赋值再次赋值
const (
a, b = iota, "iota"
c, d
)
fmt.Println(a, b, c, d)
//0 iota 1 iota
若为如下情况,编译器无法推导e的值,产生错误
const (
a, b = iota, "iota"
c, d, e//err
)
使用隐匿变量控制iota的值
func main() {
const (
_ = 0
a = iota
_
_
b = iota
)
fmt.Println(a, b)
}
//1 4
单独的常量赋值,认为是单独的一批
func main() {
const a = iota
const b = iota
fmt.Println(a, b)
}
// 0 0
基本类型
类型 | 描述 |
---|---|
uint8 / uint16 / uint32 / uint64 | 无符号 8 / 16 / 32 / 64位整型 |
int8 / int16 / int32 / int64 | 有符号8 / 16 / 32 / 64位整型 |
float32 / float64 | IEEE754 32 / 64 位浮点型数 |
complex64 / complex128 | 32 / 64 位实数和虚数 |
byte | 类似 uint8 |
rune | 类似 int32 |
uintptr | 无符号整型,用于存放一个指针 |
指针
与C相同,Go语言让程序员决定何时使用指针。变量其实是一种使用方便的占位符,用于引用计算机内存地址。Go 语言中的的取地址符是&
,放到一个变量前使用就会返回相应变量的内存地址。
但go语言指针的使用类似于引用
指针变量其实就是用于存放某一个对象的内存地址。
func main() {
var a = 1
var p = &a
var p1 *int
fmt.Println(a, p, p1)
p1 = p
fmt.Println(a, p, p1)
}
//1 0xc0000a4000 <nil>
//1 0xc0000a4000 0xc0000a4000
若定义但为赋值,默认为nil(即null)
数组
数组使用与c语言类似
格式
var variable_name [SIZE] variable_type
go语言数组可对数组内一下标进行初始化
//声明数组
var ar [3]int
//直接初始化
var arr = [3]int{1} //[1 0 0]
var arr1 = [3]int{1, 1: 2}//[1 2 0]
//使用简短声明进行初始化
brr := [3]int{1, 2}//[1 2 0]
brr1 := [3]int{0: 3, 1: 4}//[3 4 0]
//未知长度是时,使用[...]进行占位
var crr = [...]int{1, 9: 3}//[1 0 0 0 0 0 0 0 0 3]
crr1 := [...]int{1, 2, 3, 4, 5}//[1 2 3 4 5]
数组名
c语言的数组名,代表一个指针,指向数组
go的数组,为一个变量类型,名称即是这个变量
所以go中使用数组名赋值,即是拷贝整个数组,使用指针传递数组减少开销
func main() {
arr := [...]int{1, 2, 3}
var brr = arr
var p = &brr
fmt.Println(arr)
fmt.Println(brr)
fmt.Println(&brr)
fmt.Println(p)
fmt.Println(*p)
}
结构体
type Book struct {
_BookName string
_Author string
}
func main() {
book1 := Book{"红楼梦", "曹雪芹"}
fmt.Println(book1)
var book2 = Book{_BookName: "三体", _Author: "刘慈欣"}
fmt.Println(book2._BookName, book2._Author)
//结构体指针访问时使用 . 而不是->
p := &book1
fmt.Println(p._BookName, p._Author)
}
//{红楼梦 曹雪芹}
//三体 刘慈欣
//红楼梦 曹雪芹