• Go语言系列二


    字符串

    与其它主要编程语言的差异

    • string是数据类型,不是引用或指针类型
    • string是只读的byte slice,len函数可以是它包含的byte数
    • string的byte数组可以存放任何数据

    Unicode UTF8

    • Unicode是一种字符集(code point)
    • UTF8是unicode的存储实现(转换为字节序列的规则)

    编码与存储

    字符 "中"
    Unicode 0x4E2D
    UTF-8 0xE4B8AD
    string/[]byte [0xE4, 0xB8, 0xAD]

    常用字符串函数

    函数:一等公民

    与其它主要编程语言的差异

    • 1> 可以有多个返回值
    • 2> 所有参数都是值传递: slice, map, channel 会有传引用的错觉
    • 3> 函数可以作为变量的值
    • 4> 函数可以作为参数和返回值

    学习函数式编程

    • book <计算机程序的构造和解释>

    函数: 可变参数及defer

    可变参数

    func sum(ops ...int) int {
        s := 0
        for _, op := range ops {
            s += op
        }
        return s
    }
    

    defer 函数

    func TestDefer(t *testing.T) {
        defer func() {
            t.Log("Clear resources")
        }()
        t.Log("Started")
        panic("Fatal error")	//defer仍会执行
    }
    

    封装数据和行为

    结构体定义

    type Employee struct {
        Id string
        Name string
        Age int
    }
    

    实例创建及初始化

    e := Employee{"0", "Bob", 20}
    e1 := Employee{Name: "Mike", Age: 30}
    e2 := new(Employee)		//注意这里返回的引用/指针,相当于 e := &Employee{}
    e2.Id = "2"				//与其它主要编程语言的差异:通过实例的指针访问成员不需要使用->
    e2.Age = 22
    e2.Name = "Rose"
    

    行为(方法)定义

    与其它主要编程语言的差异

    type Employee struct {
        Id string
        Name string
        Age int
    }
    
    //第一种定义方式在实例对应方法被调用时,实例的成员会进行值复制
    func (e Employee) String() string {
        return fmt.Sprintf("ID:%s-Name:%s-Age:%d", e.Id, e.Name, e.Age)
    }
    
    //通常情况下为避免内存拷贝我们使用第二种定义方式
    func (e *Employee) String() string {
        return fmt.Sprintf("ID:%s/Name:%s/Age:%d", e.Id, e.Name, e.Age)
    }
    
    

    Duck Type 式接口实现

    //接口定义
    type Programmer interface {
        WriteHelloWorld() Code
    }
    
    //接口实现
    type GoProgrammer struct {
        
    }
    
    func (p *GoProgrammer) WriteHelloWorld() Code {
        return "fmt.Println("Hello World!")"
    }
    

    Go 接口

    与其它主要编程语言的差异

    • 1> 接口为非入侵性, 实现不依赖与接口定义
    • 2> 所以接口的定义可以包含在接口使用者包内

    接口变量

    自定义类型

    1. type IntConvertionFn fun(n int)	int
    2. type MyPoint int
    

    多态

    空接口与断言

    • 1> 空接口可以表示任何类型
    • 2> 通过断言来将空接口转换为制定类型
    v, ok := p.(int)	//ok=true 时为转换成功
    

    Go接口最佳实践

    倾向于使用小的接口定义,很多接口只包含一个方法

    type Reader interface {
        Read(p []byte)(n int, err error)
    }
    
    type Writer interface {
        Write(p []byte)(n int, err error)
    }
    

    较大的接口定义,可以由多个小接口定义组合而成

    type ReadWriter interface {
        Reader
        Writer
    }
    

    只依赖于必要功能的最小接口

    func StoreData(reader Reader) error {
        ...
    }
    

    Go的错误机制

    与其它主要编程语言的差异

    • 1> 没有异常机制
    • 2> error类型实现了error接口
    • 3> 可以通过errors.New来快速创建错误实例
    type error interface {
        Error() string
    }
    
    errors.New("n must be in the range[0, 11]")
    

    最佳实践

    定义不同的错误变量,以便于判断错误类型

    var LessThanTwoError error = errors.New("n must be greater than 2")
    var GreaterThanHundredError error = errors.New("n must be less than 100")
    ...
    func TestGetFibonacci(t *testing.T) {
        var list []int
        list, err := GetFibonacci(-10)
        if err == LessThanTwoError {
            t.Error("Need a larger number")
        }
        if err == GreaterThanHundredError {
            t.Error("Nedd a larger number")
        }
    }
    

    及早失败,避免嵌套

    panic

    • 1> panic 用于不可以恢复的错误
    • 2> panic退出前会执行defer指定的内容

    **panic vs os.Exit **

    • 1> os.Exit退出时不会调用defer指定的函数
    • 2> os.Exit退出时不输出当前调用栈信息

    recover

    /* !< java */
    try {
        ...
    } catch(Throwable t) {
        
    }
    
    /* !< C++ */
    try {
        ...
    } catch(...) {
        
    }
    
    /* !< golang */
    defer func() {
        if err := recover(); err != nil {
            //恢复错误
        }
    }()
    

    最常见的"错误恢复"

    defer func {
        if err := recover(); err != nil {
            log.Error("recoverd panic", err)
        }
    }()
    //这种错误修复非常危险
    

    当心! recover成为恶魔

    • 1> 形成僵尸服务进程,导致health check失效
    • 2> "Let it Crash!"往往是我们恢复不确定性错误的最好方法
  • 相关阅读:
    如何在外部获取当前A标签的ID值
    获取<a>标签值</a>的标签值及更改
    Mysql : Maximum execution time of 30 seconds exceeded
    Ajax+PHP实现的进度条--实例
    HTML控件 隐藏
    Ajax学习--理解 Ajax 及其工作原理
    XMLHttpRequest 对象属性参数参考
    七、smarty--缓存的控制
    六、smarty-缓存控制前的页面静态化原理
    Java 的 List 与 Scala 的 Seq 相互转换
  • 原文地址:https://www.cnblogs.com/xzpin/p/11602069.html
Copyright © 2020-2023  润新知