积木成楼
首页 / golang

golang base (two)

2019-06-08 · golang · 约 20 分钟

map

    // 直接声明并赋值
    m := map[string]int{"one":1,"two":2,"three":3}
    t.Log(m, len(m))//map[one:1 two:2 three:3] len 3
    // 声明并赋予零值
    m1 := map[string]int{}
    m1["one"] = 1
    t.Log(m1, len(m1))//map[one:1] len 1
    // slice map
    m2 :=make(map[string]int,5/*cap 实际上预先设定了5的容量*/)// map 类型 ,len
    t.Log(m2,len(m2))//map[] len 0
    m3 := map[int]int{}
    t.Log(m3[1]) // 0
    m3[2] = 0
    t.Log(m3[2]) // 0
    m3[3] = 0;
    // 判断存在或者为 零值
    if v, ok := m3[3]; ok {
        t.Log(v, "key 3 is exist.")
    } else {
        t.Log("KEY 3 is not existing.")
    }
    // 在访问 不存在的 key 的时候 会返回对应的零值 而不是异常
    m := map[string]int{"one": 1, "two": 2, "three": 3}
    for k, v := range m {
        t.Log(k, "=>", v)
    }
    m := map[int]func(op int) int{}//
    m[1] = func(op int) int {
        return op
    }
    m[2] = func(op int) int {
        return op * op
    }
    m[3] = func(op int) int {
        return op *op* op
    }
    t.Log(m[1](2),m[2](2),m[3](2))// 2 4 8
// 元素是唯一的
// 1) 添加元素
// 2) 判断元素是否存在
// 3) 删除元素
// 4) 元素个数
    mySet := map[int]bool{}
    mySet[1] = true
    mySet[3] = true
    n:= 3
    if mySet[n]{
        t.Logf("%d is existing",n)
    }else {
        t.Logf("%d is not existing",n)
        t.Log(mySet[n])
    }

    t.Log(len(mySet))
    delete(mySet, n)

    if mySet[n]{
        t.Logf("%d is existing",n)
    }else {
        t.Logf("%d is not existing",n)
        t.Log(mySet[n])
    }

字符串

    var s string
    t.Log(s)// ""
    s = "hello"
    // s[1] = '2'//can't assign s[1]
    t.Log(len(s))// 5
    s = "\xE4\xB8\xA5"
    t.Log(s,len(s))// 严 3 len 是 byte 长度
    // Unicode 是一种字符集(code point) 只规定了对应关系,没有规定怎么实现
    // UTF8 是 unicode 的存储实现(转换为字节序列的规则)

    s ="中"
    t.Log(len(s))// byte 数 3

    c:=[]rune(s)
    t.Log(len(c))// 1
    t.Log("rune size :", unsafe.Sizeof(c))// 24 3*8 就是 3 byte 24字节

    t.Logf("中 unicode %x",c[0])
    t.Logf("中 UTF8 %x",s)

    // 遍历string的时候,实际自动把string转成了rune再遍历。
    // 而不是根据 len(string)的byte数组个数
    s = "中华人民共和国"
    for _,v := range s {
        t.Logf("%[1]c %[1]x",v)
    }

    // strings strconv
    // 字符串分割 string
    s = "A,B,C"
    parts := strings.Split(s,",")// []string 的切片
    t.Logf("%T", parts)
    for _,v := range parts{
        t.Logf("%T", v)// string
    }
    // 合并
    t.Log(strings.Join(parts,"-"))
    // 转换
    s1 := strconv.Itoa(10)// Itoa AtoI
    t.Log("str "+ s1)
    if s2,err := strconv.Atoi(s1);err == nil{
        t.Log(10+s2)
    }

函数

// 支持多返回值
func returnMultiValues() (a, b int) {
    return rand.Intn(10), rand.Intn(20)
}
// 可以作为参数与返回值
func timeSpent(inner func(op int) int) (func(op int) int){
    return func(n int) int {
        start := time.Now()
        ret := inner(n)
        fmt.Println("time Spent:",time.Since(start).Seconds())
        return ret
    }
}
func slowFun(op int)int{
    time.Sleep(time.Second*1)
    return  op
}
func TestFn(t *testing.T) {
    i, l := returnMultiValues()
    t.Log(i, l)

    tsSF := timeSpent(slowFun)
    t.Log(tsSF(10))
}

可变长参数与 defer

// 可变长参数 参数类型一致
func Sum(ops ...int)(res int){
    res = 0
    for _,v := range ops{
        res += v
    }
    return
}
func TestFn1(t *testing.T){
    t.Log(Sum(1,2,3,4,5))
    t.Log(Sum(1,2,3,4,5,6))
}


func Clear(){
    defer fmt.Println("errs")
    fmt.Println("close")
    panic("err")
}
func Clear2(){
    defer fmt.Println("errs2")
    fmt.Println("close2")
    panic("err")
}

func TestDefer(t *testing.T){
    defer Clear()
    defer Clear2()
    fmt.Println("Start")
    panic("err")
}
// 执行顺序为
// Start close2 errs2 close errs
// defer 类似于栈结构 先进后出
// 在 defer 中引发 panic 只会导致当前的 defer 体里面的程序中断

面向对象

封装数据和行为(方法)

// 数据封装
type Employee struct {
    Id   string
    Name string
    Age  int
}

func TestCreateEmployeeObj(t *testing.T){
    e:= Employee{"0","张三",23}
    e1 := Employee{Id:"张三",Name:"李四",Age:25}
    e2 := new(Employee) // 返回的是一个指针
    e2.Age = 29
    e2.Name = "王五"
    e2.Id = "3"
    t.Log(e)
    t.Log(e1)
    t.Log(e2)
    t.Logf("e is %T", e)
    t.Logf("e2 is %T", e2)
}

//    main_test.go:437: {0 张三 23}
//    main_test.go:438: {张三 李四 25}
//    main_test.go:439: &{3 王五 29}
//    main_test.go:440: e is main.Employee
//    main_test.go:441: e2 is *main.Employee
// 行为封装
// 通过引用去使用这个方法
func (e *Employee) String() string {
    fmt.Printf("Address is %x\n", unsafe.Pointer(&e.Name))
    return fmt.Sprintf("ID:%s-Name:%s-Age:%d", e.Id, e.Name, e.Age)
}
// 通过值拷贝去使用这个方法 这种会带来更大的内存消耗
func (e Employee) String() string {
    fmt.Printf("Address is %x\n", unsafe.Pointer(&e.Name))
    return fmt.Sprintf("ID:%s-Name:%s-Age:%d", e.Id, e.Name, e.Age)
}

接口的定义

type Programmer interface {
    WriterHelloWorld() string
}

type  GoProgrammer struct {

}
func (to *GoProgrammer) WriterHelloWorld() string{
    return "fmt.Println(\"hello world!\")"
}

func TestClient(t *testing.T){
    var p Programmer
    p = new(GoProgrammer)
    t.Log(p.WriterHelloWorld())
}

接口变量

继承与组合

type Pet struct {

}

func (p *Pet) Speck()  {
    fmt.Println("...")
}

func (p *Pet) SpeckTo(host string) {
    p.Speck()
    fmt.Println(" ", host)
}

type Dog struct {
    //p *Pet // 复合
    Pet
}

func (d *Dog) Speck()  {
    fmt.Println("www")
    d.SpeckTo("laowan")
}

//func (d *Dog) SpeckTo(host string) {
//  //d.SpeckTo(host)
//  d.Speck()
//  fmt.Println(host)
//}

func TestInherit(t *testing.T){
    // var dog Pet = new(Dog) 不能使用 Dog 去作为 Pat 类型
    var dog = new(Dog)
    //dog.SpeckTo("张三") // ... 张三 匿名变量 只能调用 变量自己的方法
    dog.Speck() //www ... lanwan
    // 子类可以调用 匿名变量的方法但是这不算是完整意义上的继承

    // 关于继承这部分 跟 php 差距很大,与其说是继承,我更加倾向于说这是 组合
    // 类似于 php 中的 traits 但又不像,因为匿名变量分界线很清楚,
    // traits 是可以在被使用后 根据使用者的情况展示不同的特性
    // 是你的就是你的,是我的就是我的,你用我的,那就是我的,上层不能使用下层的方法
    // 下层在使用上层的方法时候,可以理解为全在上层使用

接口与多态

type Code string
type Programmer interface {
    WriterHelloWorld() Code
}

type GoProgrammer struct {
}

func (to *GoProgrammer) WriterHelloWorld() Code {
    return "fmt.Println(\"hello world!\")"
}

type JavaProgrammer struct {
}

func (to *JavaProgrammer) WriterHelloWorld() Code {
    return "fmt.Println(\"hello world!\")"
}

func WriterFirstProgrammer(programmer Programmer) {
    fmt.Printf("%T %v\n", programmer, programmer.WriterHelloWorld())
}

func TestPolymorphism(t *testing.T) {
    goProg := new(GoProgrammer)// 指针
    javaProg := new(JavaProgrammer)// 指针
    WriterFirstProgrammer(goProg)
    WriterFirstProgrammer(javaProg)
}

空接口与断言

Go接口最佳实践

← 返回文章列表