GO基础知识


GO基础知识

go的环境设置

系统环境变量 \Go\bin 安装go目录下的bin目录

开发环境 开发过程中go要求制定一个目录专门用来放go的代码文件目录

GOPATH 匹配到改文件夹下面的src目录 C:\Users\wxd\Desktop\goproject

此处小心 如果环境变量修改之后发现不生效 请检查 是否有用户环境变量覆盖掉了,以及检查开发IDE是否也有GOPATH配置

一个go程序至少有一个程序入口 便是 package main 下的 func main (文件夹名和文件名可以不叫main也可以叫其他的)

Golang面向对象

(1) Golang也支 持面向对象编程(OOP),但是和传统的面向对象编程有区别,并不是纯粹的面向对象语言。所以我们说Golang支持面向对象编程特性
是比较准确的。
(2) Golang没有类(class), Go语言的结构体(struct)和其它编程语 言的类(class)有同等的地位,你可以理解Gelang是基于struct来实现0OP特性的。
(3) Golang面向对象编程非常简洁,去掉了传统OOP语言的方法重载、构造函数和析构函数、隐藏的this指针等等
(4) Golang仍然有面向对象编程的继承,封装和多态的特性,只是实现的方式和其它OOP语言不一样,比如继承:Golang没有extends 关键字,继承
是通过匿名字段来实现

go的基本属性

数据类型

基本数据类型

数值

整数 有符号int8 int16 int32 int64 int 无符号uint8 uint16 uint32 uint64 uint byte

浮点数 float32 float64

字符型

用byte来表示字符型

布尔型

true false

字符串

string (在go当中string是基本数据类型) 在go中,不支持字符串直接和其他类型做字符串拼接

派生数据类型-复杂数据类型

指针

(个人理解就是Java当中的地址值) *int表示指针 某个int值的指针 *string表示指针 某个string值的指针

取地址操作符&和取值操作符*是一对互补操作符,&取出地址,*根据地址取出地址指向的值。

可以通过指针修改数据

name := "ssss"
named := &name
*named = "ddddd"
数组
数组内存分析 数组每个空间占用的字节数取决于数组类型

数组初始化方式

长度属于类型的一部分

Go中数组属值类型,在默认情况下是值传递,因此会进行值拷贝。

切片(动态数组)

切片(slice)是golang中一种特有的数据类型

切片(slice)是对数组一个连续片段的引用,所以切片是一个引用类型。 这个片段可以是整个数组,或者是由起始和终止索引标识的一些项的子集。需要注意的是,终止索弓|标识的项不包括在切片内。切片提供一个相关数组的动态窗口

内存分析

切片的声明

方式1:定义一个切片,然后让切片去引用一个已经创建好的数组。

方式2:通过make内置函数来创建切片。基本语法: var切片名[type = make([]类型, len,[cap])

make底层创建一 个数组,对外不可见,所以不可以直接操作这个数组,要通过slice去间接的访问各个元素,不可以直接对数组进行维护、操作

方式3:定一个切片,直接就指定具体数组,使用原理类似make的方式。

切片可以继续切片
切片可以动态增长

可以通过append函数将切片追加给切片

如果没有指定cap,则cap默认为len,每次扩容的大小为cap的值,原空间容量如果小于1000,新切片是之前的2倍,否则是原来的1.25倍

切片的拷贝

切片在传参上是引用传递,不同长度的动态数组的形参是一致的

判断空

map

map的创建方式

key、value的类型: bool、 数字string、 指针、channel 、还可以是只包含前面几个类型的接口、结构体、数组
key通常为int、string类型, value通常为数字(整数、浮点数)、string、 map、结构体
key不可以是slice、map、 function

map的特点:

(1) map集合在使用前一定要make
(2) map的key-value是无序的(其实是按照key的hashcode排的--个人理解)
(3) key是不可以重复的,如果遇到重复,后-一个value会替换前一个value
(4) value可以重复的

map的操作

[1]增加和更新操作:
mapl["key"]= value - -> 如果key还没有, 就是增加,如果key存在就是修改。
[2]删除操作:
delete(map,"key") , delete是一个内置 函数,如果key存在,就删除该key-value,如果k的y不存在,不操作,但是也不会报错
[3]清空操作:
(1)如果我们要删除map的所有key ,没有一个专门的方法一次删除, 可以遍历一下key,逐 个删除
(2)或者map = make(..), make一个新的,让原来的成为垃圾,被gc回收
[4]查找操作:
value ,bool = map[key]
value为返回的value, bool为是否返回,要么true 要么false

[5]获取长度

通过len()获取长度

[6]便利

map只支持for range便利

参数传递

是一个引用传递

结构体
定义一个结构体

创建一个结构体实例
package main

import "fmt"

type Teacher struct {
	Name   string
	Age    int
	school string
}

func main() {
	// 第一种创建方式
	var t1 Teacher = Teacher{}
	t1.Name = "t1"
	t1.Age = 18
	t1.school = "s1"
	fmt.Println(t1)
	// 第二种创建方式
	var t2 Teacher = Teacher{"t2", 28, "S2"}
	fmt.Println(t2)
	// 第三种创建方式 返回的是结构体指针
	var t3 *Teacher = new(Teacher)
	//t是指针,t其实指向的就是地址,应该给这个地址的指向的对象的字段赋值:
	(*t3).Name = "t3"
	(*t3).Age = 38
	//为了符合程序员的编程习惯,go提供了简化的赋值方式:
	t3.school = "s3" //go编译器底层对t.school转化(*t) school = "s3"
	fmt.Println(*t3)
	fmt.Println(*&t3)
	// 第四种创建方式 返回的是结构体指针
	var t4 *Teacher = &Teacher{}
	(*t4).Name = "t4"
	(*t4).Age = 48
	t4.school = "s4"
	fmt.Println(*t4)
	fmt.Println(*&t4)

}
结构体相互转化

结构体是用户单独定义的类型,和其它类型进行转换时需要有完全相同的字段(名字、个数和类型)
a = a(b)
结构体进行type重新定义(相当于取别名),Golang认为是新的数据类型, 但是相互间可以强转

管道
函数
接口

关键字

也叫保留字 go一共25个关键字

const

const声明的是一个常量

可以使用const来定义一个枚举

goto

goto 可以无条件的转到程序中指定的行 和条件语句还有标签配合使用 不建议使用

defer

在函数中,程序员经常需要创建资源,为了在函数执行完毕后,及时的释放资源,Go的设计者提供defer关键字

ruturn 比 defer先执行

interface

通用万能类型 interface{} 空接口 (类似Java的Object)

类型断言
//interface{}是万能数据类型
func myFunc(arg interface{}) {
	fmt.Println("myFunc is called...")
	fmt.Println(arg)
	//interface{}改如何区分此时引用的底层数据类型到底是什么?
	//给interface{} 提供“类型断言”的机制
	value, ok := arg.(string)
	print(value, ok)
}

预定义标识符

一共37个预定标识符 包含基础数据类型和系统内嵌函数

iota(不建议使用)

iota只能在const()中使用

第一行的iota默认值为0,每行的iota都会累加1

示例:

可以自定义iota的表达式

nil

表示为空

运算符

go中没有三目运算符

++ -- 自增自减只能写在变量的后面 不可以写在变量的前面 切只能单独使用 不能参与到运算当中去

基本语法

if

if 条件表达式 {

? 执行语句

条件表达式不需要加括号了

switch

case 上的条件可以有多个 用逗号(,)分隔开 case结束的时候不需要break跳出

switch 可以不带表达式 case 上写表达式 可以当作if使用

switch穿透 利用fallthroungh关键字 会执行下一个case

for循环

go只有for循环 没有while do while循环

for的初始表达式 不能用var来定义 只能用 := 来定义

for 可以灵活定义

func main() {
   sum := 0
   var i = 1
   for i <= 5 {
      sum += i
      i++
   }
   print(sum)

}

for range

for range 可以遍历数组 切片 字符串 map 通道 类似于其他语言的foreach

for key, value := range 数组 切片 字符串 map 通道 {

函数

函数的定义

func 函数名 (形参列表)(返回值列表){

函数可以有多个返回值

首字母大写可以被其他包访问 首字母小写只能在本包访问

函数不支持重载

在go中不支持重载

函数也也是一种数据类型

在go中函数也也是一种数据类型 可以赋值给另一个函数类型的变量 通过该变量可以对函数调用

函数返回值命名

函数的返回值可以命名,命名之后,无需在return的时候手动返回

init函数

初始化函数 可以用来进行一些初始化的操作

每一个源文件都可以包含一个init函数,该函数会在main函数执行前被go运行框架调用

多个源文件都有init函数

会先调用main包import引入的init函数 main包中自己的init函数后执行

匿名函数

也可以将匿名函数赋值给一个变量 通过变量来调用 可以重复调用

闭包

匿名函数中引用的那个变量会一直保存在内存中, 可以一直使用

本质|

闭包本质依旧是一个匿名函数, 只是这个函数引入外界的变量/参数

匿名函数+引用的变量/参数=闭包

特点:

返回的是一个匿名函数,但是这个匿名函数引用到函数外的变量/参数,因此这个匿名函数就和变量/参数形成一个整体, 构成闭包

闭包中使用的变量/参数会一直保存在内存中, 所以会一直使用----> 意味着闭包不可滥用(对内存消耗大)

常用函数

字符串相关

使用系统内置函数是不用导包的,直接用就行

[1]统计字符串的长度按字节进行统计:
len[(str)

[2]字符串遍历:
r:= []rune(str)
[3]字符串转整数:
n, err := strconv.Atoi("66")
[4]整数转字符串:
str = strconv.ltoa(6887)
[5]查找子串是否在指定的字符串中:
strings.Contains("javaandgolang", "go")
[6]统计一个字符串有几个指定的子串:
strings.Count("javaandgolang","a")
[7]不区分大小写的字符串比较:
fmt.Println(strings.EqualFold("go" , "Go"))
[8]返回子串在字符串第一-次出现的索引值, 如果没有返回-1 :
strings.lIndex(' javaandgolang", "a")

[9]字符串的替换:
strings. Replace(" goandjavagogoy', "go", "golang", n)
n可以指定你希望替换几个,如果n=-1表示全部替换,替换两个n就是2
[10]按照指定的某个字符,为分割标识,将一个学符串拆分成字符串数组:
strings.Split(" go-python-java", "-")
[11]将字符串的字母进行大小写的转换:
strings.ToLower("Go")// go
strings.ToUpper" go")//Go
[12]将字符串左右两边的空格去掉:
strings.TrimSpace(" go and java ")
[13]将字符串左右两边指定的字符去掉:
strings.Trim(" golang "," ~")
[14]将字符串左边指定的字符去掉:
strings.TrimLeft(" golang "," ~")
[15]将字符串右边指定的字符去掉:
strings.TrimRight(" golang"," ~")
[16]判断字符串是否以指定的字符串开头:
strings.HasPrefix("http://java.sun.com/jsp/jstl/fmt", "http")

[17]判断字符串是否以指定的字符串结束:
strings.Hassuffix(" demo.png", ".png")

日期时间相关

时间和日期的函数,需要到入time包

获取当前时间,就要调用函数Now函数

Format()格式化 传入格式各个数字是固定的,必须这样写 选择任意的组合都是可以的

内置函数

len()

new()

别名

自定义数据类型 相当于起别名

type myint int

但是编译的时候认为是2种数据类型,不可以随意转换 要强制转换 myint()

也可以给函数起别名

也可以导包的时候起别名

_ 代表匿名别名 . 代表将包中所有的函数导入到当前包中可以直接使用函数,不需要 xxx.xxx()调用

go包目录

函数导入包 导入的是包的目录

同一文件夹下的包名必须一致

可以给包起别名 原来的包名就不能用了

错误处理

错误处理/捕获机制

go中追求代码优雅,引入defer+recover机制

自定义错误

自定义错误

捕获错误且中断程序

下划线

“_”是特殊标识符,用来忽略结果。

下划线在import中

  import 下划线(如:import hello/imp)的作用:当导入一个包时,该包下的文件里所有init()函数都会被执行,然而,有些时候我们并不需要把整个包都导入进来,仅仅是是希望它执行init()函数而已。这个时候就可以使用 import 引用该包。即使用【import _ 包路径】只是引用该包,仅仅是为了调用init()函数,所以无法通过包名来调用包中的其他函数。

匿名变量

在使用多重赋值时,如果想要忽略某个值,可以使用匿名变量(anonymous variable)。 匿名变量用一个下划线_表示