Nace's CookBook
CookBook
这里会记录一些Nace经常碰到的一些不容易记住的编程相关的 专业术语 和 小Tips ;
About Code
位运算符
|位运算符|语义/Semantics|e.g.| |---|---|---| |&|按位与/AND|0101 & 0011 = 0001| |I|按位或/OR|0101 I 0011 = 0111| |^|按位异或/XOR|0101 ^ 0011 = 0110| |^&|位清除/AND NOT|0110 &^ 1011 = 0100| |<<|位左移/LEFT SHIFT|0001 << 3 = 1000| |>>|位右移/Right SHIFT| 1000 >> 3 = 0001|
TIPS: 位清除(bit clear/AND NOT) 与 异或(XOR) 虽然结果表现的一致 但是 实际表述并不一样。
位移操作的右操作数必须要是uint
类型
About Arch
Best Practice in Golang
- 类型转换
在一些高性能场景中,类型转换不能使用type(foo)的形式,可以考虑用unsafe包 从底层存储方式进行转换 会高效很多:
- 构建字符串
字符串相加在数量很多的场景下,性能会变得非常差,因为每次都会给新的string重新分配内存。所以,在需要相加的字符串很多的情况下,用strings
包的Join()
或者bytes
包的WriteString()/WriteBytes()
,一次性分配好需要分配的内存就会让性能提升很多.
- 避免Goroutine中的延迟求值
在日常的开发中 我们往往需要在一个LOOP中实现并发 这时候往往这么写:
但是这样就会遇到一个问题:得到的foo永远都是index==len(foos)-1
的foo值,这是因为goroutine的延迟求值,这里每次go func的匿名方法并不会被马上执行,当LOOP 执行完的时候才会去执行展开其中的Goroutine.所以正确的写法应该是每次执行go func
的时候把foo带进去,让goroutine去保存这个状态。具体的代码如下:
- 关于反射的一些知识
反射是在Runtime层读取对象的内存信息与类型;但是由于没有对象的头指针,无法做到靠其自身来解析对象的类型。依靠interface{}
来实现反射,i interface{}
可以保存参数的类型和数据
这里的
interface{}
只是对象的一个复制,并且是不可寻址的,所以,要改变对象的信息只能传入指向此对象的指针
|
|
利用reflect来导出不可导出类型 任何pkg相对于reflect来说都是外部包。
- Golang中的AOP(面向切面编程)
在Golang中,反射(reflect)很好地切合了AOP的主题。通过reflect
在Runtime的时候动态执行方法,当我们用AOP的思想抽象出一个切面之后,也许这个切面是一个日志模块,或是一个审计模块(这些模块具有一个共同点:永远不需要也不可能被需要耦合到业务代码中去)。也可以把这些模块看成一个代码hook,这些模块在不用更改业务代码的同时调用业务代码中的逻辑。一次简单的尝试如下:
- 在Golang中使用Set
首先,Golang中是没有built-in
的set
关键字的。所以,要实现类似set
的数据结构,需要使用map
和key
来组合成一个set
。
这里的set更多的指的是一个FIFO的map也就是一个ordered-map。
比如,我们现在有一个map:
然后,我们发现遍历这个map的时候,key的顺序有可能是会被更换的:
|
|
这是为什么呢?其实仔细想一想就知道,我们为什么要指望map
来向set
一样来工作呢?这本来就是两个数据结构啊!所以,我们要的是什么?在这种场景下,我们需要的只是key按一定顺序排列的map中对应的值,经过这层思考之后,就可以很快的得出代码:
再反过来想想 我们为什么希望map按照FIFO顺序来呢?终究是对map的理解出现了误解。 这时候静下来 好好读读Go blog的说明,就会有豁然开朗的感觉了吧:)