go-time包
[TOC]
Go 的时间操作基本上都用 time 包。
*time.Location 类型
在 Go 中,表示时区的类型是 type Location struct{...}
,代码中使用 *time.Location
对象。
对于不严格的场景而言,可以获取服务器所处的时区。但是本文不建议这个方法。因为一台服务器服务的时区是事先可知的,或者说是需要对接的时区信息也是已知的(比如对接微信,那么时间肯定是东八区,而不是 UTC 时间)。获得东八区时区的代码如下:
loc, _ := time.LoadLocation("Asia/Shanghai")
之后这个 loc 可以作为常量使用。是否能够拿到时区,取决于机器本地的 zoneinfo 文件。后文也将使用这个 loc
作为全局变量。在docker环境下,没有zoneinfo文件,所以需要自定义一个时区名称,比如我们人工添加一个巴西利亚时间:
brazil := time.FixedZone("Brazil/Brasilia", -3*60*60)
这里我们同时要知道一个很重要的概念,就是在 *Location
的加持下,一个 Time
类型本身是同时记录着 UTC 时间和本地时间的,这就使得一个 Go 时间类型不会因为时区而出现歧义,比如你可以用一个东八区的 Time
和西八区的 Time
随意进行运算也不会出错。这一特性使得时间类型变得极为实用。
go信号处理示例
[TOC]
golang信号signal的处理
在实际项目中我们修改了配置文件后,希望在不重启进程的情况下重新加载配置文件,这时候就需要通过信号传递来进行处理了。golang中对信号的处理主要使用os/signal包中的两个方法:
一个是notify方法用来监听收到的信号;
一个是 stop方法用来取消监听。下面给一个些示例。
go反射
go标准库-reflect
[TOC]
Golang 接口与反射知识要点
这篇文章以 Go 官方经典博客 The Laws of Reflection 为基础,详细介绍文中涉及的知识点,并有所扩展。
interface
首先,我们谈谈接口类型的内存布局(memory layout),其他基础类型、Struct、Slice、Map、指针类型的内存布局会在以后单独分析。接口变量的值包含两部分内容:赋值给接口类型变量的实际值(concrete value),实际值的类型信息(type descriptor)。两部分在一起构成接口的值(interface value)。
接口变量的这两部分内容由两个字来存储(假设是 32 位系统,那么一个字就是 32 位),第一个字指向 itable
(interface table)。itable 表示 interface 和实际类型的转换信息。itable 开头是一个存储了变量实际类型的描述信息,接着是一个由函数指针组成的列表。注意 itable 中的函数和接口类型相对应,而不是和动态类型。例如下面例子,itable 只关联了 Stringer 中定义的 String 方法,而 Binary 中定义的 Get 方法则不在其中。对于每个 interface 和实际类型,只要在代码中存在引用关系, go 就会在运行时为这一对具体的 <Interface, Type> 生成 itable 信息。
第二个字称为 data
,指向实际的数据。例子中,赋值语句 var s Stringer = b 实际上对b做了拷贝,而不是对b进行引用。存放在接口变量中的数据大小可能任意,但接口只提供了一个字来专门存储真实数据,所以赋值语句在堆上分配了一块内存,并将该字设置为对这块内存的引用。
go指针
[TOC]
Go学习笔记–go指针:unsafe.Pointer
简单示例
Go语言是个强类型语言。也就是说Go对类型要求严格,不同类型不能进行赋值操作。指针也是具有明确类型的对象,进行严格类型检查。下面的代码会产生编译错误 :
package main
import (
"fmt"
)
func main() {
u := uint32(32)
i := int32(1)
fmt.Println(&u, &i) // 打印出地址
p := &i // p 的类型是 *int32
p = &u // &u的类型是 *uint32,于 p 的类型不同,不能赋值
p = (*int32)(&u) // 这种类型转换语法也是无效的
fmt.Println(p)
}