Golang反射的使用的正确姿势

Golang反射的使用的正确姿势

Go本身不支持模板,因此在以往需要使用模板的场景下往往就需要使用反射(reflect). 反射使用多了以后会容易上瘾,有些人甚至会形成一种莫名其妙的鄙视链。文人相轻,看来在需要动手指的领域历来如此:) 。反射有两个问题,在使用前需要三思:

  1. 大量的使用反射会损失一定性能
  2. Clear is better than clever. Reflection is never clear.

Go的类型设计上有一些基本原则,理解这些基本原则会有助于你理解反射的本质:

  1. 变量包括 <type, value> 两部分。理解这一点你就知道为什么nil != nil了。
  2. type包括 static typeconcrete type. 简单来说 static type是你在编码是看见的类型,concrete type是runtime系统看见的类型。
  3. 类型断言能否成功,取决于变量的concrete type,而不是static type. 因此,一个 reader变量如果它的concrete type也实现了write方法的话,它也可以被类型断言为writer.
  4. Go中的反射依靠interface{}作为桥梁,因此遵循原则3. 例如,反射包.Kind方法返回的是concrete type, 而不是static type.

Talk is cheap, show some code:

Golang中使用gorm小结

Golang中使用gorm小结

项目中使用orm的好处很多:

  1. 防止直接拼接sql语句引入sql注入漏洞
  2. 方便对modle进行统一管理
  3. 专注业务,加速开发

坏处也是显而易见的:

  1. 开发者与最终的sql语句隔了一层orm,因此可能会不慎引入烂sql
  2. 依赖于orm的成熟度,无法进行一些「复杂」的查询。当然,复杂的查询一大半都是应该从设计上规避的

留意不合法的时间值

MySQL的DATE/DATATIME类型可以对应Golang的time.Time。但是,如果DATE/DATATIME不慎插入了一个无效值,例如2016-00-00 00:00:00, 那么这条记录是无法查询出来的。会返回gorm.RecordNotFound类型错误。零值0000-00-00 00:00:00是有效值,不影响正常查询。

留意tagsql:"default:null"

gorm对各种tag的支持非常完善。但是有些行为跟直觉不太一致,需要注意。当对某字段设置tagsql:"default:null"时,你想通过update设置该字段为null就不可能了,只能通过raw sql。这是gorm设计的取向问题。

如何通过gorm设置字段为null

字段允许为null值肯定是设计存在问题。但是,往往前人埋下的坑需要你去填。gorm作者给出了两种方法,以string为例:

  1. 在golang中,声明该字段为*string
  2. 使用sql.NullString类型

推荐使用后者。

留意连接串中的loc

例如通过如下连接串打开mysql连接:

parseTime=true&loc=Local说明会解析时间,时区是机器的local时区。机器之间的时区可能不一致会设置有问题,这导致从相同库的不同实例查询出来的结果可能解析以后就不一样。因此推荐将loc统一设置为一个时区,如parseTime=true&loc=America%2FChicago

基于httpd的Erlang Web Server

Background

  1. 有一堆数据需要用Golang来处理,数据是使用Erlang的term_to_binary保存的。
  2. 数据是热数据,因此不能一次性对数据进行binary_to_term预处理。
  3. Erlang的Ports是不太合适的,因为Ports的设计更侧重于Erlang主动与外部进程(一般是其他语言编写的)进行通信。
  4. 基于通用协议使得Golang与Erlang直接可以通信是唯一的出路,通用协议如http, thrift, protobuf等都可以,因此这条出路还挺宽。BERT-RPC强大而笨重,但是没有Golang的RPC Client. 由于需求非常简单,考虑基于Erlang httpd写一个简单的Web Server完成这个任务。

如果不是Erlang, 这个任务应该是分分钟搞定,但是Erlang的官方文档缺乏example, 相关的文章又太少。难怪有人会吐槽:

When I first started using Erlang it took a fair bit of trial and error to create a server that generated dynamic HTTP content. The main problem is the lack of good tutorials out there for doing these kinds of things. The documentation that comes with Erlang is good for reference, but is not that helpful if you’re just learning the language.

How

下面是将用户输入的内容返回给用户的echo server代码:

  1. httpd实现了一套处理http request的behavior, 通过配置可以设置如何路由这些请求。这里使用esi的方式来处理请求。erl_script_alias依赖mod_esi. 因此{modules,[mod_esi]}不能省去。上例将/esi/echoserver:func交给echo_server:func处理。因此,可以通过 http://localhost:8080/esi/echo_server:echo?abcd你好321 进行测试。
  2. httpd定义了一堆mod_*来处理请求,modules之间的顺序有限制的,启用多个模块需要注意。
  3. mod_esi:deliver()第一段内容必须设置Header:

    Use this callback function to dynamically generate dynamic web content. When a part of the page is generated send the data back to the client through deliver/2. Note that the first chunk of data sent to the client must at least contain all HTTP header fields that the response will generate. If the first chunk does not contain the End of HTTP header, that is “\r\n\r\n”, the server will assume that no HTTP header fields will be generated.

  4. 如果返回的内容有unicode字符,需要使用unicode模块处理,否则浏览器会乱码。

References

[1] Working example for Erlang Server Interface

[2] “Hello World” Webapp in Erlang