GO语言特性
开发者使用编程语言的三大分类(执行速度,简易程度,开发难度)
1.执行速度快、编译速度慢(编译型):C,C++
2.执行速度较慢,编译速度快(解释型):JAVA,.NET
3.执行速度慢,开发难度小(动态脚本):Python,PHP
GO语言在三个条件做了平衡:易于开发,快速编译,高效执行
1.helloworld
package main
import "fmt"
func main {
fmt.Println("hello world")
}
注意:
1.如果需要将程序编译成二进制程序,要将包名写成main包
第一个Go程序解读:
1.package
Go源文件开头必须使用package声明代码所属包,包是Go代码分发的最基本单位。若程序需要运行,则包名必须为main。
2.import
import用于导入程序所依赖的所有包,此程序依赖fmt包。
3.func
func用于定义函数,main函数是程序的入口,若程序需要运行必须声明main函数,main函数无参数也无返回值
4.fmt.Println
调用fmt.Println函数将参数信息打印到控制台
编译&运行:
# go build helloworld.go
# go build -o test.exe helloworld.go (test.exe文件)
# go run helloworld.go
2.go 变量定义,变量限定适用范围
变量是指堆一块存储空间定义名称。
变量定义方式:
func main() {
var name string = "kk"//定义了类型也定义了初始值
var zerostring string // 定义变量类型,但不初始值
var typestring = "kk" //定义变量省略类型,不能省略初始值
//短声明(必须在函数内使用)
shortstring := "kk"
fmt.Println(name,zerostring,typestring,shortstring)
}
变量需要先定义再使用,直接使用会报错
var name string = "abc"
name = "bca"
批量定义
var (
变量名1 变量类型1 = 值1
变量名2 变量类型2 = 值2
)
变量作用域:
变量查找会从函数内查找,没有才会去查找函数外的相同变量
子块可以覆盖父块中使用的变量
变量标识符:
标识符:程序中定义的名字,变量名,常量名字,自定义类型,接口
规范:
1.必须满足:组成只能由非空的unicode编码字符串,数字,下划线组成
2.必须满足:必须以unicode编码的字符串或下划线开头(不能以数字开头)
3.必须满足:不能与go的关键字冲突(package,func,var)
建议:
1.Ascill编码(a-z,A-Z)数字,下划线
2.变量使用驼峰式
myName
3.与go内置变量不要冲突
函数级别:
func main {
var msg string = "hello workd"
fmt.Println(msg)
}
包级别:
var packageVar string = "package Var"
func main {
var msg string = "hello workd"
fmt.Println(msg, packageVar)
}
子块级别:
var packageVar string = "package Var"
func main {
var msg string = "hello workd"
{
var blockvar string = "block"
fmt.Println(packageVar,blockvar)
}
fmt.Println(msg, packageVar)
}
}
3.go 常量
常量一旦定义后不能修改
常量定义:
①常量
package main
import "fmt"
const (
packName string = "package"
packMsg = "pack"
A = "test"
B // 使用前一个常量的值进行初始化 B->A
C // 使用前一个常量的值进行初始化 C->B
D = "test2"
E
F
) //使用前一个常量的值进行初始化
func main() {
const name string = "abc"
fmt.Println(name, B, C, E, F)
}
②枚举
package main
import "fmt"
func main() {
const (
Mon = iota //在常量内使用iota,初始化为0,每次调用+1
Tuesd
Wed
Thur
Fir
Sat
Sun
)
fmt.Println(Mon)
}
4.go 变量打印
fmt.Printf("%T, %v, %#v", name, name, name)
占位符
%T:打印变量类型
%v:按某种格式打印变量
%#v:按某种格式打印变量
5.go 数据类型
布尔类型:
package main
import "fmt"
func main() {
isGirl := false
fmt.Println("%T,%#v", isGirl, isGirl)
}
整数类型:
//int
/int8,int16,int32,int64
常用操作:
1.算数运算符:+,-,*,/,%,++,--
2.关系运算符:>,<,==,!=
3.位运算符:&,|
4.赋值运算符:=,+=,-=,*=
浮点数类型:
package main
import (
"fmt"
)
func main() {
var height float32 = 1.68
fmt.Printf("%T %#v %f\n", height,height,height)
}
逻辑运算:
与:左操作数与右操作数为true,结果为true
或:左操作数与右操作数只要有一个为true,结果为true
非:取反
package main
import "fmt"
func main() {
a, b, c, d =: true, true ,false ,false
fmt.Println("a, b", a && b)
fmt.Println("a, c", a && c)
}
6.条件语句
①if语句
package main
import "fmt"
func main() {
var y string
fmt.Print("买西瓜么:")
fmt.Scan(&y)
fmt.Println("你输入的是", y)
if y == "yes" {
fmt.Println("买一个西瓜")
}
}
初始化子语句
可以在if语句中初始化语句块内的局部变量,多个语句之间使用逗号分隔(;)
if flag := true;flag {
fmt.Println("flag:",flag)
}
②选择语句switch case
package main
import "fmt"
func main() {
var y string
fmt.Print("请输入:")
fmt.Scan(&y)
switch y {
case "yes", "y":
fmt.Println("输入的是1")
case "no", "n":
fmt.Println("输入的是no")
default:
fmt.Println("2222")
}
}
7.循环语句for,break,continue
package main
import "fmt"
func main() {
for i := 0; i < 10; i++ {
fmt.Println("1234")
}
var index = 1
for index <= 10 {
if index == 5 {
break
}
if index == 6 {
continue
}
fmt.Println(index)
index++
}
}
for-range
用于遍历可迭代对象中的每个元素,例如字符串,数组,切片,映射,通道等
package main
import "fmt"
func main() {
var letters string
letters = "伍俊錡"
for _, k := range letters {
fmt.Printf("%q", k)
}
}
针对包含unicode字符的字符串便利,时需要使用for-range,range返回两个元素分别为字节索引和rune字符,可通过空白标识符忽略需要接受的变量。
类while,死循环
func main() {
for {
total += index
index ++
if index > 100 {
break
}
}
}
8.goto跳转
package main
import "fmt"
func main() {
total := 0
index := 0
max := 100
START:
index += 1
total += index
if index == max {
goto END
}
goro START
END:
fmt.Println("total")
}
9.数组类型
1)声明
数组声明需要指定组成元素的类型以及存储元素的数量(长度)。在数组声明后。其长度不可修改,数组的每个元素会根据对应类型的零值进行初始化。
var names [10]string
var scores [10]int
初始化元素
names = []string{"1","2","3"}
空切片,已经初始化但是元素数量为0
names = []string{}
赋值数组
names = []string{1: "05", 100: "abc"}
2)字面量
a)指定数组长度:[length]type{v1,v2,v3}
例 var user [3]string = [3]string{"kk","ee","rr"}
b)使用初始化元素数量推到数组长度[...]type{v1,v2,v3}
例 bounds := [...]int{10, 20, 30, 40}
c)对指定位置元素进行初始化[length]type{a:1, b:2, c:3}
例 names = []string{1: "05", 100: "abc"}
2)操作
a)关系运算 ==, !=
fmt.Println(bounds == [...]int{10, 20, 30})
fmt.Println(bounds != [...]int{10, 20, 30})
b)获取数组长度
使用len函数可获取数组长度
fmt.Println(len(bounds))
c)访问&修改
通过编号对数组元素进行访问和修改
fmt.Println(bounds[0], bounds[len(abc) - 1])
bounds[0] = "abc"
d)切片获取数组的一部分元素作为切片
fmt.Printf("%T, %q\n",lang[1:3], lang[1,3])
e)遍历
可以通过for+len+访问方式或for-range方式对数组中元素进行遍历
for i := 0; i < len(langs); i++ {
fmt.Printf("%d:%q\n", i, langs[i])
}
for i, v := range langs {
fmt.Printf("%d: %q\n",i, v)
}
使用for-range遍历数组,range返回的两个元素分别为数组元素索引和值
10.映射(map)
映射是存储一系列无序的key/value对,通过key来对value进行操作(增删改查)映射的key只能为可使用==运算符的类型,value可以为任意类型
1)声明
map声明需要指定组成元素key,value的类型,在声明后,会被初始化为nil,表示暂不存在的映射
var tels map[string]string
var points map[[2]int]float64
fmt.Printf("%T, %t, %v\n", tels, tels == nil, tels)
2)初始化
使用字面量初始化
tels = map[string]string{"kk":"11111", "ll":"gggg"}
fmt.Printf("%q\n", tels)
使用make函数进行初始化
weight := make(map[string]float64)
fmt.Println(weight)
3)操作
a)获取元素的数量
使用len函数获取映射元素的数量
fmt.Println(len(tels))
b)访问
sudents := map[int]string{1: "kk", 2: "rr"}
students01 := map[int]map[string]string{1: map[string]string{"name": "kk"}}
fmt.Printf("%v, %q, %q\n", students, students[1], students[2])
当访问key存在映射时则返回对应的值,否则返回值类型的零值
c)判断key是否存在
通过key访问元素可接受两个值,第一个值为value,第二个值为bool类型标识元素是否存在,存在为true,不存在为false
student, ok := student[1]
fmt.Printf("%t, %v\n", ok, student)
d)修改&增加
使用key对映射负值时当key存在则修改key对应value,若key不存在则增加key和value
students[1] = "kl" //key存在,修改
students[3] = "pp" //key不存在,增加
e)删除
使用delete函数删除映射中已经存在的key
delete(students, 1)
delete(students, 4)
fmt.Println(students)
f)遍历
使用for-range对映射中各个元素进行遍历,range返回两个元素分别为映射的key和value
for k, v := range students {
fmt.Printf("%v:%v\n", k, v)
}
11.函数定义
函数包含函数名,行参列表,函数体和返回值列表,使用func进行声明,函数无参数或返回值时则形参列表和返回值列表省略
func name(parameters) returns {
}
形参列表需要描述参数名及参数类型,所有形参为函数块局部变量,返回值需要描述返回值类型
举例
1.无参 无返回值
func sayHello() {
fmt.Println("hello world")
}
2.有参 无返回值
func say(name string, name2 string) {
fmt.Println("hello world:", name, name2)
}
3.有参 有返回值
func add (a int, b int) int {
return a + b
}
func main() {
say("abc", "vbn")
num = add(1, 2)
fmt.println(num)
}
12.函数调用
函数通过函数名(实参列表)在调用过程中实参的每个数据会赋值给形参中的每个变量,因 此实参列表类型和数量需要函数定义的形参一一对应。
举例
1.调用无参无返回值函数
sayHello()
2.调用有参无返回值类型
say("kk", "abc")
3.调用有参有返回值函数
n1, n2 := 1, 2
fmt.Printf("%d + %d = %d\n", n1, n2, add(n1+n2))
13.函数参数
1.参数类型合并
// 连续多个变量类型相同
// 保留最后一个元素类型,前面的类型都可以省略
// func add (a int, b int) int
func add (a, b int) int {
return a + b
}
func test(p1, p2 int, p3, p4 string) {
fmt.Println("%T, %T, %T, %T", p1, p2, p3, p4)
}
2.可变参数类型
// 1.可变参数,在一个方法中只能有一个
// 2.并且可变参数必须放在函数声明参数列表最后
func test(args ...string) {
fmt.Println("%T, %#v", args, args)
}
//至少有n个参数
//add
func add(n1, n2 int, args ...int) int {
total := n1 + n2
for _, v := range args {
total += v
}
return total
}
func mult(n1, n2 int) int {
return n1 * n2
}
func main() {
test()
test("1")
test("1", "2")
fmt.Println(add(1,2,3,4))
}
14.函数返回值
1.多个返回值
func calc(n1, n2 int) (int, int) {
//a, b := 1, 2
r1 := mult(1, 2)
r2 := add(1, 2)
return r1, r2
}
15.函数类型
1.声明&初始化&调用
//定义函数类型变量,并使用零值nil进行初始化
var callback func(n1, n2 int) (r1, r2, r3, r4 int)
fmt.Printf("%T, %v", callback, callback)
//赋值为函数calc
callback = calc
fmt.Println(callback(5, 2)) //调用calc函数
2.值类型与引用
import "fmt"
func main() {
// 在内存中申请内存新的空间,将a的值拷贝到b中
// 在修改a 不影响b
// 在修改a 影响b
//值类型 b = a,tmpAge修改不影响age
age := 30
tmpAge := age
tmpAge = 31
fmt.Println(age, tmpAge)
//引用类型 修改tmpUsers影响users
users make([]string, 10)
tmpUsers := users
tmpUsers[0] = "kk"
fmt.Printf("%#v, %#v\n", users, tmpUsers)
}
3. 值类型,函数内修改实参的值
func change(value int) {
value += 1
}
func changePointer(pointer *int) {
*pointer = *pointer + 1
}
func main() {
value := 1
change(value)
fmt.Println(value) // 1
changePointer(&value)
fmt.Println(value) // 2
}
4.函数作为形参
package main
import "fmt"
func calc(n1 int, n2 int, callback func(int, int) int) int {
// 不定义是什么运算
// 通过函数参数传递我要进行运算
rt := callback(n1, n2)
if rt >= 0 && rt <= 100 {
return rt
}
return -1
}
func add(n1, n2 int) int {
return n1 + n2
}
func multi(n1, n2 int) int {
return n1 * n2
}
func main() {
fmt.Println(calc(1, 2, add))
fmt.Println(calc(10, 100, multi))
}
5.定义函数变量
package main
import "fmt"
func calc(n1 int, n2 int, callback func(int, int) int) int {
// 不定义是什么运算
// 通过函数参数传递我要进行运算
rt := callback(n1, n2)
if rt >= 0 && rt <= 100 {
return rt
}
return -1
}
//第一种
func main() {
add := func(n1, n2 int) int {
return n1 + n2
}
multi := func(n1, n2 int) int {
return n1 * n2
}
fmt.Println(calc(1, 2, add))
fmt.Println(calc(10, 100, multi))
}
//第二种
func main() {
fmt.Println(calc(1, 2, func(n1, n2 int) int {
return n1 + n2
}))
fmt.Println(calc(10, 100, func(n1, n2 int) int {
return n1 * n2
}))
}
16.函数闭包
package main
import "fmt"
func addBase(base int) func(int) int {
return func(n int) int {
return base + n
}
}
func main() {
add1 := addBase(1)
fmt.Println(add1(5))
add10 := addBase(10)
fmt.Println(add10(3))
}
17.函数错误处理
1.error接口
Go语言通过error接口实现错误处理的标准模式,通过使用函数返回值列表中的最后一个值返回错误信息,将错误的处理交由程序员主动进行处理
error接口初始化方法
a)通过errors包的New方法创建
b)通过fmt.Errorf方法创建
//定义除法函数,若除数为0则使用error返回错误信息
func div(n1, n2 int) int {
if n2 == 0 {
return -1, errors.New("除数为0")
}
return n1 / n2, nil
}
func main() {
if rt, err = div(1, 0); err == nil {
fmt.Println("nil")
}
else {
fmt.Println(err)
}
}
2.defer
defer关键字用户声明函数,不论函数是否发生错误都在函数最后执行(return之前),若使用defer声明多个函数,则按照声明的顺序,先声明后执行(先进后出),常用来做资源释放,日记记录工作
在函数退出时执行
func main() {
//defer 函数调用
defer func() {
fmt.Println("defer")
}
fmt.Println("main")
}
延迟执行,先输出main,在输出defer
func main() {
//defer 函数调用
defer func() {
fmt.Println("defer")
}()
defer func() {
fmt.Println("defer A")
}()
defer func() {
fmt.Println("defer B")
}()
fmt.Println("main")
}
输出:
main
deferB
deferA
defer
defer是先进后出结构
3.panic与recover函数
go语言提供panic和recover函数用于处理运行时错误,当调用panic抛出错误,中断原有的控制流程,常用于不可修复性错误。recover函数用于终止错误处理流程,仅在defer语句的函数中有效,用于截取错误处理流程,recover只能捕获到最后一个错误。
a)panic
package main
import "fmt"
func main() {
defer func() {
fmt.Println("defer 01")
}()
panic("error go")
}
b)recover
//当未发生panic则recover函数得到的结果为nil
func success() {
defer func() {
}()
fmt.Println("success")
}
//当发生panic则recover函数得到的结果为panic传递的参数
func failure() {
defer func() {
fmt.Println(recover())
}()
fmt.Println("failure")
panic("error")
}
//revover只能获取最后一次的panic信息
func failure2() {
defer func() {
fmt.Println(recover())
}()
defer func() {
fmt.Println("failure 2")
}()
fmt.Println("failure")
panic("error")
}