golang的学习
Posted weixin_45747080
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了golang的学习相关的知识,希望对你有一定的参考价值。
非0基础的Golang的学习
Golang的优势
- 极简单的部署方式
- 可直接编译成机器码
- 不依赖其他库
- 直接运行可部署
- 静态类型的语言
- 编译时能检查出隐藏的大多数问题
- 语言层面的并发
- 天生支持
- 充分利用多核
- 强大的标准库
- runtime系统调度机制
- 高效的GC垃圾回收
- 丰富的标准库
- 简单易学
- 25个关键字
- C语言简洁基因,内嵌C语法支持
- 面向对象特征(继承、封装、多态)
- 跨平台性
- “大厂”领军
- Google、fackbook
- Tencent、Baidu(运维)、JD
main包
go run hello.go
go build hello.go
./hello
定义变量
var a int //方法一:声明变量,默认是0
var b int = 100 //方法二:声明变量,初始化一个值
var c = 100 //方法三:省去数据类型,根据值去自动匹配数据类型
d := 100 //方法四(常用):省去var关键字,自动匹配数据类型
var {
v1 = 10
v2 string = "abcd"
v3 = true
}
Tips
方法四只能在函数体中声明使用(局部变量),全局变量不能声明和使用。
常量中使用iota
在const( )中添加一个关键字iota
,每行的iota都加1,第一行的iota默认值是0。(强调每行)
const a = 100
//多常量定义
const (
b = 100
c = 100
)
func main() {
const (
a = iota //iota = 0
b //iota = 1
c
d
)
fmt.Println("a =",a) //0
fmt.Println("b =",b) //1
fmt.Println("c =",c) //2
fmt.Println("d =",d) //3
const (
e = 10 * iota // iota = 0, e= 0
f // iota = 1, f = 10
g
)
fmt.Println("e =",e) //0
fmt.Println("f =",f) //10
fmt.Println("g =",g) //20
const (
h , i = iota +1 , iota +2 //iota = 0, h = iota+1=0+1=1, i=iota+2=0+2=2
j , k //iota = 1, j = iota+1=1+1=2,l=iota+2=1+2=3
)
fmt.Println("h =",h) //1
fmt.Println("i =",i) //2
fmt.Println("j =",j) //2
fmt.Println("k =",k) //3
}
多返回值
package main
import "fmt"
//单返回值((返回int类型)
func f1(s string, i int) int {
fmt.Println("s =", s)
fmt.Println("i =", i)
//一个返回值
return 0;
}
//多返回值(匿名)
func f2(s string, i int) (int, int) {
fmt.Println("s =", s)
fmt.Println("i =", i)
//一个返回值
return 0, 1;
}
//多返回值(具名)
func f3(s string, i int) (r1 int, r2 int) {
//两个返回值
r1 = 0
r2 = 1
return;
}
//多返回值(同类型,且具名)
func f4(s string, i int) (r1,r2 int) {
fmt.Println("r1 =", r1)
fmt.Println("r2 =", r2)
//两个返回值
r1 = 0
r2 = 1
return;
}
func main() {
s := "test"
i := 100
r1 := f1(s, i)
fmt.Println("r1 =",r1)
r2, r3 := f2(s, i)
fmt.Println("r2 =",r2, "r3 =",r3)
f3(s,i)
f4(s,i)
}
Tips
具名多返回值实质上是局部变量(有初始值)
init函数
init函数在import导包中的调用流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2sEK761V-1635763248563)(C:\\Users\\wqk\\AppData\\Roaming\\Typora\\typora-user-images\\image-20211012053532973.png)]
包中可以使用init函数来进行包的一些初始化工作
import导包
import (
"5-init/lib1" //使用原包名导入,调用方法为lib1.Api()
_ "5-init/lib2" //匿名导入包,即需要调用该包中的init(),但是不使用其中的接口
. "5-init/lib3" //将当前包导入并且和本包合并,直接使用Api()调用其中接口。(不推荐,可能出现命名重复 )
mylib "5-init/lib4" //自定义导入的包名。使用mylib.Api()调用
)
Tips
Golang中,如果import导入了包但没有使用会报错,所以导入的包必须使用,或者使用
_
进行匿名导入(只调用包中的init函数,不使用其中其他函数)
指针
&a //传递a变量的地址(实参)
*p //存储a变量的地址(形参)
*p = 10 //通过修改a变量的地址的值的方式来修改a的值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xuj7CAY8-1635763248566)(C:\\Users\\wqk\\AppData\\Roaming\\Typora\\typora-user-images\\image-20211012062746855.png)]
defer语句
defer类似于C++的析构函数
和Java的finalize()
函数类似
多次调用defer语句的执行顺序是类似栈
package main
import "fmt"
func f1() {
fmt.Println("f1 called...")
}
func f2() {
fmt.Println("f2 called...")
}
func f3() {
fmt.Println("f3 called...")
}
func main() {
defer f1()
defer f2()
defer f3()
/*
f3 called...
f2 called...
f1 called...
*/
}
defer在return返回值返回后执行
package main
import "fmt"
func deferFunc() int {
fmt.Println("defer func called...")
return 0
}
func returnFunc() int {
fmt.Println("return func called...")
return 0
}
func test() int {
defer deferFunc()
return returnFunc()
}
func main() {
test()
/*
return func called...
defer func called...
*/
}
数组及其遍历
数组的定义方式
var myArray1 [10]int //数组定义方式一:固定长度的数组(没有赋值,但有默认值0)
myArray2 := [4]int{1,2,3,4} //数组定义方式二:固定长度数组并赋值
myArray3 := []int{1,2,3,4} //数组定义方式三:动态数组(没有固定长度)
获取数组长度
//len()返回数组长度
length := len(myArray1)
fmt.Println("myArray1 len =",length)
数组遍历
// 数组遍历方式一:fori遍历
for i := 0; i < length; i++ {
fmt.Println(myArray1[i])
}
// 数组遍历方式二:for range,可以返回index(下标)和value(元素)
for index, value := range myArray1 {
fmt.Println("index =",index, "value =",value)
}
// 数组遍历方式三:for range,匿名返回index或者value
for _, value := range myArray1 {
fmt.Println("value =",value)
}
for index, _ := range myArray1 {
fmt.Println("index =",index)
}
固定数组传参
//传递固定长度数组必须严格匹配数组类型以及数组长度的
func printArray(array [4]int) {
//值拷贝
for i := 0; i < len(array); i++ {
fmt.Println(array[i])
}
}
func main() {
myArray2 := [4]int{1,2,3,4}
printArray(myArray2) //只能传递长度为4的数组
}
动态数组传参
//传递动态数组不需要匹配数组长度
func printSlice(slice []int) {
//引用拷贝
fmt.Println("printSlice called...")
for i := 0; i < len(slice); i++ {
fmt.Println(slice[i])
}
}
func main() {
myArray3 := []int{1,2,3,4}
printSlice(myArray3) //传递动态数组
}
动态数组slice
声明方式
//声明一个切片且初始化,默认值是1,2,3
slice1 := []int{1,2,3}
fmt.Println("=====================")
for index, value := range slice1 {
fmt.Println("index =",index,"value =",value)
}
//声明一个切片但没有初始化且没有初始空间
var slice2 []int
//手动利用make来分配空间,元素有默认值
slice2 = make([]int,5)
fmt.Println("=====================")
for index, value := range slice2 {
fmt.Println("index =",index,"value =",value)
}
//声明一个切片同时给切片分配空间
var slice3 []int = make([]int, 5)
fmt.Println("=====================")
for index, value := range slice3 {
fmt.Println("index =",index,"value =",value)
}
//声明一个切片,同时分配空间,自动匹配类型
slice4 := make([]int,5)
fmt.Println("=====================")
for index, value := range slice4 {
fmt.Println("index =",index,"value =",value)
}
slice追加、截取和拷贝
slice的len和cap的概念,类似于Java的ArrayList(动态数组)的size和capacity。len代表slice中是实际元素的个数,而cap代表这个slice中能够存储的元素大小,同时也支持动态扩容,在len达到cap时扩容,可以在初始化slice为其指定cap,否则默认的cap等于len
初始化slice时没有指定cap
//初始化slice1,没有指定cap(默认cap与len相等)
var slice1 []int = make([]int,3)
fmt.Printf("len = %d, cap = %d, slice = %v\\n",len(slice1),cap(slice1),slice1)
/*
output
len = 3, cap = 3, slice = [0 0 0]
*/
初始化slice时指定cap
//初始化slice2,指定cap为5
var slice2 []int = make([]int,3,5)
fmt.Printf("len = %d, cap = %d, slice = %v\\n",len(slice2),cap(slice2),slice2)
/*
output
len = 3, cap = 5, slice = [0 0 0]
*/
向slice中添加元素(append)
slice2 = append(slice2,5)
向元素已满的slice中添加元素(会自动扩容)
//向已满(len=cap)的slice中添加元素,slice会自动扩容(按照一定规则)
slice1 = append(slice1, 5)
fmt.Printf("len = %d, cap = %d, slice = %v\\n",len(slice1),cap(slice1),slice1)
/*
output
len = 4, cap = 6, slice = [0 0 0 5] (可以看到cap变大了)
*/
从slice中截取元素(:)
slice3 := []int{0,1,2,3}
//左闭右开[0,2)即截取0到1的元素
fmt.Printf("slice = %v\\n",slice3[0:2]) //slice = [0 1]
//截取0到2的元素
fmt.Printf("slice = %v\\n",slice3[:2]) //slice = [0 1]
//截取0到末尾的元素
fmt.Printf("slice = %v\\n",slice3[0:]) //slice = [0 1 2 3]
//截取全部元素
fmt.Printf("slice = %v\\n",slice3[:]) //slice = [0 1 2 3]
截取后的切片指向同一元素(浅拷贝)
slice := slice3[:3]
slice[0] = 100
fmt.Printf("slice = %v\\n",slice) //slice = [100 1 2 3]
fmt.Printf("slice3 = %v\\n",slice3) //slice = [100 1 2 3]
TIps
截取后的切片slice,修改其slice[0],发现slice3[0]也被修改了,说明修改前的slice3和修改后的slice底层指向同一数组
复制copy数组(深拷贝)
slice := make([]int,len(slice3))
//copy slice3到slice中
copy(slice,slice3)
fmt.Printf("slice = %v\\n",slice) //slice = [0 1 2 3]
map
map的格式是 map[type of key]type of value
,如map[string]string
即key为string类型,value为string类型的map集合
声明
//方式一:声明空map,在使用前分配空间后再赋值
var map1 map[int]string
map1 = make(map[int]string,10)
//map1 = make(map[int]string) //两种方式都可以
map1[1] = "Java"
map1[2] = "Golang"
map1[3] = "javascript"
fmt.Println(map1)
//方式二:声明map的时候同时make分配空间,后再赋值
var map2 = make(map[int]string)
map2[1] = "Java"
map2[2] = "Golang"
map2[3] = "JavaScript"
fmt.Println(map2)
//方式三:声明map时直接赋值
var map3 = map[int]string{
1: "Java",
2: "Golang",
3: "JavaScript",
}
fmt.Println(map3)
TIps
map声明完后一定要使用make()开辟内存!一定要使用make()开辟内存!一定要使用make()开辟内存!
遍历
myMap := map[string]string {
"China": "Beijing",
"USA": "DC",
"England": "London",
}
//遍历key和value
for key, value := range myMap {
fmt.Println("key =",key," value =",value)
}
删除
//删除myMap的"USA"键值对
delete(myMap, "USA")
修改
//修改"England"的值为Paris
myMap["England"] = "Paris"
引用传递
func printMap(myMap map[string]string) {
//myMap是引用传递
for key, value := range myMap {
fmt.Println(key,"->",value)
}
}
struct结构体
与类类似,Go使用结构体来实现对象
定义结构体
//定义Student这种结构体,它包含Name、Age、Score等属性
type Student struct {
Name string
Age int
Score int
}
结构体传参
type Student struct {
Name string
Age int
Score int
}
func printStudent(student Student) {
//值传递(相当于student对象的副本,无法修改其内部属性值)
fmt.Printf("%v\\n",student)
}
func changeStudent(student *Student) {
//引用传递(可以修改其内部属性值)
student.Age = 20
}
func main() {
student := Student{
Name: "wqk",
Age: 18,
Score: 50,
}
printStudent(student)
changeStudent(&student)
printStudent(student)
}
封装成类
和Java类似的,利用Struct封装了Student类,并且包装好了属性的Getter和Setter,需要注意的是,由于Setter需要修改实际对象的值,所以需要传递引用对象(指针)
type Student struct {
name string
Age int
Score int
}
func (this *Student)SetName(newName string) {
this.Name = newName
}
func (this *Student) GetName() string {
return this.Name
}
func (this *Student) SetAge(newAge int) {
this.Age = newAge
}
func (this *Student) GetAge(以上是关于golang的学习的主要内容,如果未能解决你的问题,请参考以下文章
json [Golang] golang #golang #snippets中有用的片段