1) slice append()
这个函数在 cap
不够用的时候就会重新分配内存以扩大容量,而如果够用的时候不不会重新分享内存
func TestArrayCap(t *testing.T){
//foo := make([]int, 5)
//foo[3] = 42
//foo[4] = 100
//
//bar := foo[1:4]
//bar[1] = 99
//
//t.Log(foo)
//t.Log(bar)
path := []byte("AAAA/BBBBBBBBB")
sepIndex := bytes.IndexByte(path,'/')
dir1 := path[:sepIndex:sepIndex] // 这里的cap 为 4
//dir1 := path[:sepIndex] # 这里的cap 与 path的cap一样 为 14
dir2 := path[sepIndex+1:]
fmt.Println("dir1 =>",string(dir1)) //prints: dir1 => AAAA
fmt.Println("dir2 =>",string(dir2)) //prints: dir2 => BBBBBBBBB
dir1 = append(dir1,"suffix"...)
fmt.Println("dir1 =>",string(dir1)) //prints: dir1 => AAAAsuffix
fmt.Println("dir2 =>",string(dir2)) //prints: dir2 => uffixBBBB
}
2) reflect.DeepEqual()
判断相等
func TestDeepEqual(t *testing.T){
m1 := map[string]string{"one": "a","two": "b"}
m2 := map[string]string{"two": "b", "one": "a"}
fmt.Println("m1 == m2:",reflect.DeepEqual(m1, m2))
//prints: m1 == m2: true
s1 := []int{1, 2, 3}
s2 := []int{1, 2, 3}
fmt.Println("s1 == s2:",reflect.DeepEqual(s1, s2))
//prints: s1 == s2: true
}
3) 接口编程
type Person struct{
name string
sex string
age int8
}
// 普通函数
func PrintPerson(p *Person){
fmt.Printf("name=%s, sex=%s, age=%s\n", p.name, p.sex, p.age)
}
// 成员函数 , 使用“成员函数”的方式叫“Receiver”
func (p *Person) Print(){
fmt.Printf("name=%s, sex=%s, age=%s\n", p.name, p.sex, p.age)
}
func TestInterface(t *testing.T){
var p = Person{
name: "jimmy",
sex: "male",
age: 18,
}
PrintPerson(&p)
p.Print()
}
(1)
type Country struct {
Name string
}
type City struct {
Name string
}
type Printable interface{
PrintStr()
}
func (c Country) PrintStr(){
fmt.Printf(c.Name)
}
func (c City) PrintStr(){
fmt.Printf(c.Name)
}
func TestInterface2(t *testing.T){
c1 := Country{Name:"China"}
c2 := City{Name:"China"}
c1.PrintStr()
c2.PrintStr()
}
(2) 类似继承 的 结构体嵌入
type WithName struct {
Name string
}
type Country struct {
WithName
}
type City struct {
WithName
}
type Printable interface{
PrintStr()
}
func (w WithName) PrintStr(){
fmt.Printf(w.Name)
}
func TestInterface3(t *testing.T){
c1 := Country{WithName{Name:"China"}}
c2 := City{WithName{Name:"Beijing"}}
c1.PrintStr()
c2.PrintStr()
}
(4) 面向对象编程方法的黄金法则——“Program to an interface not an implementation”
type WithName interface {
ToString() string
}
func PrintStr(w WithName){
fmt.Printf(w.ToString())
}
type Country struct {
Name string
}
type City struct {
Name string
}
func (c Country) ToString() string{
return c.Name
}
func (c City) ToString() string {
return c.Name
}
func TestInterface4(t *testing.T){
c1 := Country{Name:"china"}
c2 := City{Name:"shanghai"}
PrintStr(c1)
PrintStr(c2)
}
用 Stringable接口把“业务类型” Country 和 City 和“控制逻辑” Print() 给解耦了
(5) 接口完整性检查
type Shape interface{
Sides() int
Area() int
}
type Square struct{
len int
}
func (s *Square) Sides() int {
return 4
}
// Square 并没有实现 Shape 接口的所有方法 (area)
// 但是程序可以正常跑通
//
//func (s *Square) Area() int {
// return s.len * s.len
//}
// todo 需要强制实现接口的所有方法 var _ Shape = (*Square)(nil)
func TestComplete(t *testing.T){
s := Square{len: 5}
fmt.Println(s.Sides())
}
(6) 性能提示
如果需要把数字转字符串,使用 strconv.Itoa() 会比 fmt.Sprintf() 要快一倍左右
尽可能地避免把String转成[]Byte 。这个转换会导致性能下降。
如果在for-loop里对某个slice 使用 append()请先把 slice的容量很扩充到位,这样可以避免内存重新分享以及系统自动按2的N次方幂进行扩展但又用不到,从而浪费内存。
使用StringBuffer 或是StringBuild 来拼接字符串,会比使用 + 或 += 性能高三到四个数量级。
尽可能的使用并发的 go routine,然后使用 sync.WaitGroup 来同步分片操作
避免在热代码中进行内存分配,这样会导致gc很忙。尽可能的使用 sync.Pool 来重用对象。
使用 lock-free的操作,避免使用 mutex,尽可能使用 sync/Atomic包。 (关于无锁编程的相关话题,可参看《无锁队列实现》或《无锁Hashmap实现》)
使用 I/O缓冲,I/O是个非常非常慢的操作,使用 bufio.NewWrite() 和 bufio.NewReader() 可以带来更高的性能。
对于在for-loop里的固定的正则表达式,一定要使用 regexp.Compile() 编译正则表达式。性能会得升两个数量级。
如果你需要更高性能的协议,你要考虑使用 protobuf 或 msgp 而不是JSON,因为JSON的序列化和反序列化里使用了反射。
你在使用map的时候,使用整型的key会比字符串的要快,因为整型比较比字符串比较要快。