Go 语言笔记
Go 语言笔记
基本概念
综述
- Go 语言将静态语言的安全性和高效性与动态语言的易开发性进行有机结合,达到完美平衡。
- 设计者通过 goroutine 这种轻量级线程的概念来实现这个目标,然后通过 channel 来实现各个 goroutine 之间的通信,这个特性是 Go 语言最强有力的部分。
- Go 语言像其它静态语言一样执行本地代码,但它依旧运行在某种意义上的虚拟机,以此来实现高效快速的垃圾回收。
- 「切片」是 go 中的重要概念。
package main
import ("fmt”
“os”
)
func main() {
target := "World”
if len(os.Args) > 1 {
/* os.Args是一个参数切片 */
target = os.Args[1]
}
fmt.Println("Hello", target)
}
引号
Go语言中字符串的可以使用双引号( " )或者反引号( ` )来创建
- 双引号用来创建可解析的字符串字面量
- 反引号用来直接储存字面量
Package
- package是最基本的分发单位和工程管理中依赖关系的体现;
- 每个GO语言源代码文件开头都拥有一一个package声明,表示源码文件所属代码包;
- 同一个路径下只能存在一个package ,一个package可以拆成多个源文件组成;
- 要生成GO语言可执行程序,必须要有main的package包,且必须在该包下有main()函数;
import
- 导入的包将顺序导入
- 导入的包中包含其他包,先导入前置包
- 包中含有 init(),则先运行该函数
import alias “package name” //别名
import . "package name" //使用时不用加 PackageName.
import _ "package name" //仅调用包的 init() 函数
基本类型
// 基本类型
float32 float64 //浮点型
complex64 complex128 //复数型,实部和虚部都是float
bool //布尔型
int(取决于OS) int8 int16 rune(int32) int64 //整型
uint(取决于OS) byte(uint8) uint16 uint32 uint64 //无符号整型
uintptr(一个可以恰好容纳指针值的无符号整型)
string //字符串
error
派生类型
函数类型(func)
- Go语言中函数是一等(first-class)类型,说明可以把函数作为值来传递和使用
- Go语言中的函数可以返回多个结果
//函数类型定义
type MyFunc func(input1 string ,input2 string) string
//标准函数定义-函数类型实现
func myFunc(part1 string, part2 string) string {
return part1 + part2
}
//标准函数定义-函数类型实现(多返回值)
func myFunc(part1 string, part2 string) part1 string, part2 string {
return
}
//其他形式函数定义-函数类型实现(返回值)
func myFunc(part1 string, part2 string) (result string) {
result = part1 + part2
return
}
//初始化一个MyFunc变量
var splice MyFunc
//匿名函数类型初始化写法
var splice = func(part1 string, part2 string) string {
return part1 + part2
}
//直接调用匿名函数
var result = func(part1 string, part2 string) string {
return part1 + part2
}("1", "2")
指针类型(Pointer)
- 指针操作涉及到两个操作符——&和*
- 出现在一个类型之前就被视为符号,代表的就是对应类型的指针类型,而原类型视为指针类型的基地类型
- 对p(Person类型对象)使用 &p 得到的是 p 的指针(* Person),两者视为相反的操作
- bp.Grow()是(&bp).Grow()的速记法
- 结构体方法的使用者为该结构体类型的指针类型
- 值传递和地址传递
- 结构化类型(struct)
//分行定义属性(名称可选),行成一个一个结构体
type Person struct {
Name string
Gender string
Age uint8
}
//结构体的方法定义,可以通过 p.Grow()调用
//可以看到方法的实际接收者是Person的指针,地址传递
func (person *Person) Grow() {
person.Age++
}
// 更复杂的方法定义
func (person *Person) Move(newAddress string) string{
oldAddress := person.Address
person.Address = newAddress
return oldAddress
}
//实例化的几种方法
p := Person{Name:"Robert", Gender:"Male", Age:33}
p := Person{"Robert", "Male", 33}
p := new(Person)
//匿名结构体实例化
p := struct {
Name string
Gender string
Age uint8
}{"Robert", "Male", 33}
接口类型(interface)
- 接口类型中的方法声明是普通方法声明的简化形式,它们只包括方法名称、参数声明列表和结果声明列表
- 空接口类型即是不包含任何方法声明的接口类型,用 interface{} 表示
//不用声明一个数据类型中实现了哪个接口,只要满足了“方法集合为其超集”的条件,就建立了“实现”关系,这是典型的无侵入式的接口实现方法
type Animal interface {
Grow()
Move(string) string
}
- 判断是否实现了接口的方法
//先将p转换成空接口类型,然后才能进行判断
v := interface{}(&p)
//类型断言,result是转换的结果,ok代表实现关系与否
result, ok := v.(Animal)
//结果自然是实现了,因此只要满足方法集合要求,就算实现了该接口
数组类型
var nums = [5]float32{10.0, 2.0, 3.4, 7.0, 50.0}//标准初始化
var nums = []float32{10.0, 2.0, 3.4, 7.0, 50.0} //不指定长度的初始化
nums[3]=4.4 //赋值
// []int 和 [4]int 在 go 中是不同的类型
func main() {
var array = []int{1, 2, 3, 4, 5}
/* 未定义长度的数组只能传给不限制数组长度的函数 */
setArray(array)
/* 定义了长度的数组只能传给限制了相同数组长度的函数 */
var array2 = [5]int{1, 2, 3, 4, 5}
setArray2(array2)
}
func setArray(params []int) {
fmt.Println("params array length of setArray is : ", len(params))
}
func setArray2(params [5]int) {
fmt.Println("params array length of setArray2 is : ", len(params))
}
切片类型(slice)
slice[n] //返回切片/数组中的第n个元素
slice[n:] //返回从第n个元素到最后一个元素的切片
slice[:n] //返回从第一个元素到第 n 个元素的切片
slice[m:n] //返回 m 下标为开始的(n-m)个元素的切片
切片保留着跟原数组的关联 这里产生了容量的概念,对数组的容量进行操作,可以读取到原数组的内容
Append(slice,x,y,z……):会对切片值进行扩展并返回一个新的切片值
Copy(slice1,slice2):该函数接受两个类型相同的切片值作为参数,并会把第二个参数值中的元素复制到第一个参数值中的相应位置(索引值相同)上
字典类型(Map)
- 对于字典值来说,如果其中不存在索引表达式欲取出的键值对,那么就以它的值类型的空值(或称默认值)作为该索引表达式的求值结果
//字典的字面量,“K”意为键的类型,而“T”则代表元素(或称值)的类型
map[K]T
demo := map[int]string{1: "a", 2: "b", 3: "c"}
b := mm[2] //值的取出
e, ok := mm[5] //e 指取出的值(可能为零值),ok 表示是否存在
delete(demo,5) //删除demo 中 K 为5 的元素
通道类型(chan)
与其它的数据类型不同,我们无法表示一个通道类型的值。因此,我们也无法用字面量来为通道类型的变量赋值。我们只能通过调用内建函数make来达到目的
close(ch1)
value := <- ch1
value, ok := <- ch1
make(chan int, 0) //非缓冲的通道值的初始化方法
type Receiver <-chan int //单向接收通道
type Sender chan<- int //单向发送通道
var myChannel = make(chan int, 3)
var sender Sender = myChannel
var receiver Receiver = myChannel
类型别名
import alias "package name" //别名
type alias name //取了别名之后,和原类型视为不同类型
reflect.TypeOf() //反射,取出变量类型
变量
变量声明和赋值
const limit = 512 // 常量,其类型兼容任何数字
const top uint16 = 1421 // 常量,类型:uint16
var last float64 // 声明,此时last 为零值
var last float64 = 1.5 // 标准声明+初始化
last:= float64(1.5) // 简化标准声明+初始化
var last = 1.5 // 推断声明 float64
last:=1.5 // 简化推断声明+初始化
var hash []bool //数组声明
var hash = []bool{} //标准数组声明+初始化
hash := []bool{} //简化数组声明+初始化
var mm map[string]string //集合声明
mm:=map[int]bool{} //简化集合声明+初始化
mm:=map[int]bool{1:true,2:false,3:false} //简化集合声明+初始化
//多变量设置法
const(
Cyan = 0
Black = 1
White = 2
)
类型转换
<结果类型> := <目标类型> ( <表达式> )
var var1 int = 7
var2 := float32(var1)
空标示符 "_"
- 是一个占位符,它用于在赋值操作的时候将某个值赋值给空标示符号,从而达到丢弃该值的目的
- 全局变量必须含有 var,局部变量可以省略
变量可见性
- 首字母大写的变量是可以导出,也就是可以被其他包读到,属于共有变量
- 反之,首字母小写的变量不可导出,属于私有变量
iota
- 仅用于常量
- 每当遇到一个const 会重置为0
- 常见用法
/*1. 跳值使用*/
const(
a=iota // a=0
b=iota // b=1
_
c // c=3
)
/*2. 插队使用*/
const(
a=iota // a=0
b=3.14 // b=3.14
c // c=2
)
/*3. 表达式隐式使用*/
const(
a=iota*2 // a=0
b // b=2
c // c=4
)
/*4. 单行使用*/
const(
a,b=iota+1,iota+3 // a=1,b=3
c,d // c=2,d=4
e // e=2
)
控制语句
选择语句
- 不必写break,可以简单地进行类型判断
a:=3.14
switch a.(type){
case int:
println("it's int")
case string:
println("it's string")
default:
println("no")
}
循环语句
//死循环(true 可省略)
for true{
xxx
}
//标准循环
for i:=0;i<n;i++{
xxx
}
//数组的遍历
for key,value:=range nums{
xxx
}
goto
- 要加标签
package main
func main(){
goto One
xxx
xxx
One:{
xxx
}
}
select 分支流程控制语句
- select语句属于条件分支流程控制方法,不过它只能用于通道。它可以包含若干条case语句,并根据条件选择其中的一个执行
- 如果一条select语句中不存在default case, 并且在被执行时其中的所有case都不满足执行条件,那么它的执行将会被阻塞
- break语句也可以被包含在select语句中的case语句中。它的作用是立即结束当前的select语句
ch1 := make(chan int, 1)
ch2 := make(chan int, 1)
// 省略若干条语句
// 如果该select语句被执行时通道ch1和ch2中都没有任何数据,那么肯定只有default case会被执行
// 若通道中存在数据,则执行对应case
// 有数据的通道多于一个,那么Go语言会通过一种伪随机的算法来决定执行某个case
select {
case e1 := <-ch1:
fmt.Printf("1th case is selected. e1=%v.\n", e1)
case e2 := <-ch2:
fmt.Printf("2th case is selected. e2=%v.\n", e2)
default:
fmt.Println("No data!")
}
defer
- defer 语句会确保之后的语句执行完毕之后再执行本语句
func deferIt() {
defer func() {
fmt.Print(1)
}()
defer func() {
fmt.Print(2)
}()
defer func() {
fmt.Print(3)
}()
fmt.Print(4)
}
// output:4321
func deferIt3() {
f := func(i int) int {
fmt.Printf("%d ",i)
return i * 10
}
for i := 1; i < 5; i++ {
defer fmt.Printf("%d ", f(i))
}
}
// 标准输出上打印出 1 2 3 4 40 30 20 10
func deferIt4() {
for i := 1; i < 5; i++ {
defer func() {
fmt.Print(i)
}()
}
}
// deferIt4函数在被执行之后标出输出上会出现5555
// 因为匿名函数会直接进栈,等到出栈的时候i 就等于5 了
异常处理 error
- Go语言的函数可以一次返回多个结果。这就为我们温和地报告错误提供了语言级别的支持
- 对 err 进行判断,若不是nil 则把该错误(这里由err代表)返回给调用方
- 对于
ioutil.ReadAll()
可以直接return,说明声明的结果的数量、类型和顺序都是相同的,因此才能够做这种返回结果上的“嫁接”
func readFile(path string) ([]byte, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
return ioutil.ReadAll(file)
}
// Error 信息的生成,跟 os.ErrPermission、io.EOF 进行比较,很容易发现异常并通过errors.New()加以创建
if path == "" {
return nil, errors.New("The parameter is invalid!")
}
运行时恐慌 panic
- 内建函数panic和recover是天生的一对。前者用于产生运行时恐慌,而后者用于“恢复”它
- 同时recover()函数需要defer 调用才会生效
- 通过
panic(errors.New("Occur a panic!"))
即可生成一个恐慌 - 合理处理panic,可以有效防止程序崩溃
go 语句
- go语句的执行与其携带的表达式语句的执行在时间上没有必然联系,即go 语句执行后会在某个随机时间执行
// 时间协调语句
time.Sleep() //ms
runtime.Gosched() //让当前正在运行的Goroutine暂时“休息”一下
// sync.WaitGroup类型有三个方法可用——Add、Done和Wait
// Add会使其所属值的一个内置整数得到相应增加
// Done会使那个整数减1
// Wait方法会使当前Goroutine(这里是运行main函数的那个Goroutine)阻塞直到那个整数为0
func main() {
var wg sync.WaitGroup
wg.Add(3)
go func() {
fmt.Println("Go!")
wg.Done()
}()
go func() {
fmt.Println("Go!")
wg.Done()
}()
go func() {
fmt.Println("Go!")
wg.Done()
}()
wg.Wait()
}
Go 语言笔记的更多相关文章
- R语言笔记
R语言笔记 学习R语言对我来说有好几个地方需要注意的,我觉得这样的经验也适用于学习其他的新的语言. 语言的目标 我理解语言的目标就是这个语言是用来做什么的,为什么样的任务服务的,也就是设计这个语言的动 ...
- R语言笔记4--可视化
接R语言笔记3--实例1 R语言中的可视化函数分为两大类,探索性可视化(陌生数据集,不了解,需要探索里面的信息:偏重于快速,方便的工具)和解释性可视化(完全了解数据集,里面的故事需要讲解别人:偏重全面 ...
- Scala语言笔记 - 第一篇
目录 Scala语言笔记 - 第一篇 1 基本类型和循环的使用 2 String相关 3 模式匹配相关 4 class相关 5 函数调用相关 Scala语言笔记 - 第一篇 最近研究了下scala ...
- 014-预处理指令-C语言笔记
014-预处理指令-C语言笔记 学习目标 1.[掌握]枚举 2.[掌握]typedef关键字 3.[理解]预处理指令 4.[掌握]#define宏定义 5.[掌握]条件编译 6.[掌握]static与 ...
- 013-结构体-C语言笔记
013-结构体-C语言笔记 学习目录 1.[掌握]返回指针的函数 2.[掌握]指向函数的指针 3.[掌握]结构体的声明 4.[掌握]结构体与数组 5.[掌握]结构体与指针 6.[掌握]结构体的嵌套 7 ...
- 011-指针(上)-C语言笔记
011-指针(上)-C语言笔记 学习目标 1.[掌握]字符串常用函数 2.[掌握]指针变量的声明 3.[掌握]指针变量的初始化 4.[掌握]函数与指针 5.[掌握]指针的数据类型 6.[掌握]多级指针 ...
- 010-字符串-C语言笔记
010-字符串-C语言笔记 学习目标 1.[掌握]二维数组的声明和初始化 2.[掌握]遍历二维数组 3.[掌握]二维数组在内存中的存储 4.[掌握]二维数组与函数 5.[掌握]字符串 一.二维数组的声 ...
- 009-数组-C语言笔记
009-数组-C语言笔记 学习目标 1.[掌握]数组的声明 2.[掌握]数组元素的赋值和调用 3.[掌握]数组的初始化 4.[掌握]数组的遍历 5.[掌握]数组在内存中的存储 6.[掌握]数组长度计算 ...
- 008-进制-C语言笔记
008-进制-C语言笔记 学习目标 1.[掌握]include预处理指令 2.[掌握]多文件开发 3.[了解]认识进制 4.[掌握]进制之间的互相转换 5.[掌握]原码,反码,补码 6.[掌握]位运算 ...
随机推荐
- 一张图看懂STM32芯片型号的命名规则
意法半导体已经推出STM32基本型系列.增强型系列.USB基本型系列.增强型系列:新系列产品沿用增强型系列的72MHz处理频率.内存包括64KB到256KB闪存和 20KB到64KB嵌入式SRAM.新 ...
- CentOS7Linux中自动化运维工具Ansible的安装,以及通过模块批量管理多台主机
使用自动化运维工具Ansible集中化管理服务器 Ansible概述 Ansible是一款为类Unix系统开发的自由开源的配置和自动化工具.它用Python写成,类似于saltstack和Puppet ...
- java代码之美(5)---guava之Multiset
guava之Multiset 一.概述 Guava提供了一个新集合类型Multiset,它可以多次添加相等的元素,且和元素顺序无关.Multiset继承于JDK的Cllection接口,而不是Set接 ...
- Zabbix通过IPMI监控HPE服务器硬件
IPMI是智能型平台管理接口(Intelligent Platform Management Interface)的缩写,是管理基于 Intel结构的企业系统中所使用的外围设备采用的一种工业标准,该标 ...
- Flink生成Parquet格式文件实战
1.概述 在流数据应用场景中,往往会通过Flink消费Kafka中的数据,然后将这些数据进行结构化到HDFS上,再通过Hive加载这些文件供后续业务分析.今天笔者为大家分析如何使用Flink消费Kaf ...
- 初学Java Web(5)——cookie-session学习
HTTP 协议 Web 浏览器与 Web 服务器之间的一问一答的交互过程必须遵守一定的规则,这样的规则就是 HTTP 协议. HTTP 是 hypertext transfer protocol(超文 ...
- js反爬-从入门到精通webdriver
学习JS反爬 地址:http://openlaw.cn/login.jsp 想在指导案例中抓些内容,需要登陆 账号密码发送会以下面方式发送 所以需要找到_csrf和加密后的password,_csrf ...
- PC逆向之代码还原技术,第六讲汇编中除法代码还原以及原理第二讲,被除数是正数 除数非2的幂
目录 一丶简介 二丶代码还原讲解 1.被除数无符号 除数非2的幂 2.被除数无符号 除数为特例7 三丶代码还原总结 一丶简介 上一篇博客说的除2的幂. 如果被除数是有符号的,那么会进行调整,并使用位操 ...
- Docker最全教程——从理论到实战(四)
往期内容链接 https://www.cnblogs.com/codelove/p/10030439.html https://www.cnblogs.com/codelove/p/10036608. ...
- 页面优化,DocumentFragment对象详解
一.前言 最近项目不是很忙,所以去看了下之前总想整理的重汇和回流的相关资料,关于回流优化,提到了DocumentFragment的使用,这个对象在3年前我记得是有看过的,但是一直没深入了解过,所以这里 ...