Dawn's Blogs

分享技术 记录成长

0%

反射的基本介绍

反射就是程序在运行时,通过检查其定义的变量以及值,进而找到其对应的真实类型

reflect包

reflect包实现了运行时反射,允许程序操作任意类型的对象。典型用法是用静态类型interface{}保存一个值,通过调用TypeOf获取其动态类型信息,该函数返回一个Type类型值。调用ValueOf函数返回一个Value类型值,该值代表运行时的数据。

reflect.Type和reflect.Value

interface{}类型变量其具体类型可以使用reflect.Tpye来表示,而其具体值则使用reflect.Value来表示

1
func ValueOf(i interface{}) Value

ValueOf返回一个初始化为i接口保管的具体值的Value

1
func TypeOf(i interface{}) Type

TypeOf返回接口中保存的值的类型

reflect.Kind

reflect还有一个比较重要的类型Kind,表示具体类型

1
func (v Value) Kind() Kind

Kind返回v持有的值的分类,如果vValue零值,返回值为Invalid

  • Type代表实际类型,如包名.Student
  • Kind代表具体类型,如struct
  • 如果使基本数据类型,Type和Kind相同

NumField()和Field()

1
func (v Value) NumField() int

返回v持有的结构体类型值的字段数,如果vKind不是Structpanic

1
func (v Value) Field(i int) Value

返回结构体的第i个字段(的Value封装)。如果vKind不是Structi出界会panic

Elem()

1
func (v Value) Elem() Value

Elem返回v持有的接口保管的值的Value封装,或者v持有的指针指向的值的Value封装。如果vKind不是InterfacePtrpanic

1
2
3
4
5
6
7
8
9
10
11
12
func reflectElemTest(i interface{}) {
// 获取Value
rVal := reflect.ValueOf(i)
// 改变num的值
rVal.Elem().SetInt(20)
}

func main() {
num := 10
reflectElemTest(&num)
fmt.Println(num) // 20
}

Method()和Call()

1
func (v Value) Method(i int) Value

返回v持有值类型的第i个方法的已绑定(到v的持有值的)状态的函数形式的Value封装。如果i出界,或者v的持有值是接口类型的零值(nil),会panic

  • 方法排序是按照方法名字进行排序
1
func (v Value) Call(in []Value) []Value

Call方法使用输入的参数in调用v持有的函数。例如,如果len(in) == 3v.Call(in)代表调用v(in[0], in[1], in[2])(其中Value值表示其持有值)。如果vKind不是Funcpanic。它返回函数所有输出结果的Value封装的切片。如果v持有值是可变参数函数,Call方法会自行创建一个代表可变参数的切片,将对应可变参数的值都拷贝到里面。

经过几日的学习后,本人总结出两种可以实现线程间同步的方法:

  • sync.WaitGroup类型
  • 管道channel
    • 关闭管道
    • 带缓冲区的管道
    • 没有缓存区的管道

其中,sync.WaitGroup和带缓冲区的管道适用于多个并行线程简得同步,其他的方法只适用于两个线程的同步

阅读全文 »

管道channel基本介绍

channel的介绍

  • channel的本质就是一个队列,数据先进先出
  • 管道是线程安全的,多goroutine访问时,无需加锁

channel基本使用

1
2
3
4
5
6
7
8
// 声明
变量名 := make(chan 数据类型, cap)

// 向管道写入数据
管道变量 <- 数据

// 从管道中读取数据
变量 = <- 管道变量

注意:

  • channel是引用类型是指针,初始化后才能使用)
  • channel是有对应数据类型的
阅读全文 »

排序ORDER BY

默认查询返回地数据顺序,是数据先后添加的顺序

排序实现方法

使用ORDER BY对查询的数据进行排序,默认是升序排列

  • 升序:ASC (ascend)
  • 降序:DESC (descend)
阅读全文 »

比较运算符

比较运算符的结果会有个可能:

  • 结果为真,返回1
  • 结果为假,返回0
  • 其他情况返回NULL

符号型

  • 等于=和安全等于<=>:二者的作用是相似的,唯一的作用就是<=>可以对NULL进行判断NULL <=> NULL的返回值为1,NULL <=> 1返回值为0,不为NULL
  • 不等于<>或者!=
  • < > <= >=
阅读全文 »

基本的SELECT语句

基本格式

1
2
3
4
5
SELECT [DISTICT | ALL] 字段名1 [别名], 字段名2, ...
FROM 表名 [别名]
[WHERE 条件表达式]
[GROUP BY 列名1 [HAVING 条件表达式]
[ORDER BY 列名2 [ASC | DESC]]
阅读全文 »

螺旋矩阵

螺旋矩阵

解题思路

设定上下左右边界

  • 从左到右遍历上边界,重新定义上边界,即上边界指向下一行,若上边界越过下边界,则退出循环
  • 从上到下遍历右边界,重新定义右边界,即右边界指向左边一行,若右边界越过左边界,则退出循环
  • 同理依次遍历下边界、左边界
  • 循环指向上述步骤
阅读全文 »

sync包

sync包提供了基本的同步基元,如互斥锁。除了OnceWaitGroup类型,大部分都是适用于低水平程序线程高水平的同步使用channel通信更好一些

互斥锁Mutex

1
2
3
type Mutex struct {
// 包含隐藏或非导出字段
}

Mutex是一个互斥锁,可以创建为其他结构体的字段;零值为解锁状态。Mutex类型的锁和线程无关,可以由不同的线程加锁和解锁。

其他类型的同步单元

sync包除了提供互斥锁,还提供了

  • 读写锁RWMutex
  • 条件变量Cond
  • WaitGroupWaitGroup 对象内部有一个计数器,最初从0开始,它有三个方法:Add(), Done(), Wait() 用来控制计数器的数量。Add(n) 把计数器设置为nDone() 每次把计数器-1wait() 会阻塞代码的运行,直到计数器地值减为0
  • Once(只执行一次动作的对象)
阅读全文 »

goroutine基本介绍

Go主线程和携程

一个Go主线程上,可以有多个协程,协程是轻量级线程

主线程一旦退出,其他协程都会被杀死

为什么提出goroutine

线程数过多,意味着操作系统会不断地切换线程, 频繁的上下文切换就成了性能瓶颈

Go提供一种机制,可以在线程中自己实现调度,上下文切换更轻量,从而达到了线程数少,而并发数并不少的效果。而线程中调度的就是Goroutine(也就是协程)

Go协程特点

  • 独立空间:而goroutines为了避免资源浪费(亦或是资源缺乏),采用动态扩张收缩的策略初始量为2k,最大可以扩张到1G
  • 共享程序空间
  • 调度用户控制(用户级):因为协程在用户态由协程调度器完成,不需要陷入内核,切换调度开销小(协程只修改3个寄存器 - PC/SP/DX)
  • 协程是轻量级线程
阅读全文 »