Go一些tips

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会比字符串的要快,因为整型比较比字符串比较要快。

转自酷 壳 – COOLSHELL

Buy me a 肥仔水!