设为首页 加入收藏

TOP

golang 杂思(二)
2019-03-31 18:08:16 】 浏览:272
Tags:golang 杂思
ize = 4096 buf := make([]byte, blockSize) for { n, err := fin.Read(buf) if err != nil { return "", err } // buf[:0] == [] m.Write(buf[:n]) if n < blockSize { break } } return fmt.Sprintf("%x", m.Sum(nil)), nil }
不要问为什么那么麻烦, 因为那叫专业. 小点游戏包片段 4G, 你来个 md5 试试 

6. github.com/spf13/cast

不要用这个库, 性能全是呵呵呵.
Go 中类型转换代码其实很健全(实在没办法可以自行写反射), 举例如下
// ParseBool returns the boolean value represented by the string.
// It accepts 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False.
// Any other value returns an error.
func ParseBool(str string) (bool, error)

// ParseFloat converts the string s to a floating-point number
// with the precision specified by bitSize: 32 for float32, or 64 for float64.
// When bitSize=32, the result still has type float64, but it will be
// convertible to float32 without changing its value.
func ParseFloat(s string, bitSize int) (float64, error)

// ParseInt interprets a string s in the given base (0, 2 to 36) and
// bit size (0 to 64) and returns the corresponding value i.
func ParseInt(s string, base int, bitSize int) (i int64, err error)
可以看看 github.com/spf13/cast 源码设计水平线 ~
// ToBoolE casts an empty interface to a bool.
func ToBoolE(i interface{}) (bool, error) {

    i = indirect(i)

    switch b := i.(type) {
    case bool:
        return b, nil
    case nil:
        return false, nil
    case int:
        if i.(int) != 0 {
            return true, nil
        }
        return false, nil
    case string:
        return strconv.ParseBool(i.(string))
    default:
        return false, fmt.Errorf("Unable to Cast %#v to bool", i)
    }
}
首先看到的是 b := i.(type) 断言, 触发一次反射. 
随后可能到 case int 分支 i.(int) or case string 分支 i.(string) 触发二次反射. 
非常浪费. 因为 b 就是反射后的值了. 猜测作者当时喝了点酒.

其实作者写的函数还有个商榷地方在于调用 indirect 函数找到指针指向的原始类型.
// From html/template/content.go
// Copyright 2011 The Go Authors. All rights reserved.
// indirect returns the value, after dereferencing as many times
// as necessary to reach the base type (or nil).
func indirect(a interface{}) interface{} {
    if a == nil {
        return nil
    }
    if t := reflect.TypeOf(a); t.Kind() != reflect.Ptr {
        // Avoid creating a reflect.Value if it's not a pointer.
        return a
    }
    v := reflect.ValueOf(a)
    for v.Kind() == reflect.Ptr && !v.IsNil() {
        v = v.Elem()
    }
    return v.Interface()
}
这个函数引自 Go 标准库 html/template/content.go 中. 
用于将非 nil 指针转成指向类型. 提高代码兼容性. 
这是隐藏的反射. 个人觉得用在这里很浪费 ~

Go 开发中反射是低效的保证. 反射性能损耗在
    1' 运行时安全检查
    2' 调用底层的类型转换函数
不到非用不可, 请不要用反射. 和锁一样都需要慎重

外部库太多容易造成版本管理复杂, 而且生产力和效率也不一定提升. 例如上面的包 ~

... ...

其实我们的协议层, 是太爱客户端了. int, number, string 全都兼容. 
把原本 json 协议要做的事情, 抛给了运行时问题. 这方面, 强烈推荐 json 协议语义明确. 
方便我们后端做参数健壮性过滤. 避免部分 CC 攻击.

7. MySQL 相关讨论

在数据业务设计时. 顺带同大家交流下 MySQL 设计过程中小技巧(模板)
create table [table_nane] (
    id bigint unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '物理主键',
    update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
    create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    [delete_time timestamp DEFAULT NULL COMMENT '删除时间']

    [template]

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
问题 1: 物理主键 id 为什么是 unsigned ?
回答  : 
    1' 性能更好, unsigned 不涉及 反码和补码 转码消耗
    2' 表示物理主键更广 [-2^63, 2^63-1] -> [0, 2^64-1]
    3' mysql 优化会更好. select * from * where id < 250;
        原先是 select * from * where -2^63 <= id and id < 250;
        现在是 select * from * where 0 <= id and id < 250;

问题 2: 为什么用 timestamp 表示时间?
回答  :
    1' timestamp 和 int 一样都是 4字节. 用它表示时间戳更友好.
    2' 业务不再关心时间的创建和更新相关业务代码. 省心, 省代码

问题 3: 为什么是 utf8mb4 而不是 utf8? 
回答  : 
    mysql 的 utf8 不是标准的 utf8. unicode 编码定义是使用 1-6 字节
首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇WaitGroup 下一篇Golang设计模式—简单工厂模式(Si..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目