golang进阶之路

类型转换

go语言提供了一种在不同但是相互兼容的类型之间相互转换的方式,并且这种转换非常安全。非数值类型之间的转换不会丢失精读。 但是对于数值类型之间的转换,可能会发生丢失精度或其他问题。

转换语法

resultOfType := Type(exportession)

例如

x := uint16(6500)
y := int16(x)

由于x超出了int16的范围,所以y的值会被设置成-535。
对于数字,本质上将我们可以将任意的整型或者浮点型数据转换成别的整型或浮点型(要考虑丢失精度问题)。

string类型转换

一个字符串可以转换成一个[]byte(其底层位UTF-8的字节)或者一个[]rune(Unicode码点),并且[]byte和[]reune都可以转换成一个字符串类型。单个字符是一个rune类型数据(即int32), 可以转换成一个单字符的字符串。

类型转换的高级用法

Go语言的interface{}类型用于表示空接口,同时也可以用来表示任意Go类型的值。 此外,我们可以使用类型断言类型开关或者GO语言的reflect包的类型检查将一个interface{}类型的值转换成一个实际数据的值。

1、类型断言

语法

resultOfType, boolean := expression.(Type)  //安全类型断言 这里的Type是一个具体的Go类型,如int
resultOfType := expression.(Type)  //非安全类型断言,失败是panic

成功的安全类型断言将返回目标类型的值和表示成功的true。如果安全类型断言失败(即表达式的类型与声明的类型不兼容),将返回目标类型的零值和false。
非安全类型断言要么返回一个目标类型的值,要么panic抛出异常。

示例

var i interface{} = 99
var s interface{} = []string{"left", "right"}
j := i.(int) //j是int类型的数据(或者panic)
fmt.Printf("%T -> %d \n", j, j)

if i, ok := i.(int); ok{
fmt.Prinf("%T -> %d \n", i, j)   //i 是一个int类型的影子变量
}
if s, ok := s.([]string); ok{
fmt.Prinf("%T -> %q \n", s, s)  //s 是一个[]string类型的影子变量
}

输出

int -> 99
int -> 99
[]string -> ["left" "right"]

做类型断言时将结果复制给与原始变量同名的变量是很常见的事情,即使用影子变量。
上面示例中,如果我们输出原始的i和s变量(两者都是interface{}类型),它们可以以int和[]string类型的形式输出。因为fmt包的打印函数遇到interface{}类型时,会智能的打印实际类型的值。

2、类型开关

当我们使用interfa{}类型的变量时,我们常常需要访问其底层值。如果知道其底层值类型,就可以使用类型断言,但是如果其类型可能是很多类型的一种,就可以使用类型开关。

语法

switch optional; typeSwitch{
case typeList:
...
case typeList:
default:

示例

package main

import "fmt"

func main() {
    classfier(10, "string", 1.2)
}

func classfier(items ...interface{}) {
    for i, x := range items {
        switch x.(type) {
        case bool:
            fmt.Printf("param #%d is a bool\n", i)
        case float64:
            fmt.Printf("param #%d is a float64\n", i)
        case int, int8, int16, int32, int64:
            fmt.Printf("param #%d is a int\n", i)
        case string:
            fmt.Printf("param #%d is a string\n", i)
        case nil:
            fmt.Printf("param #%d is a nil\n", i)
        default:
            fmt.Printf("param #%d is a unknow\n", i)

        }
    }
}

输出

param #0 is a int
param #1 is a string
param #2 is a float64

这里使用的类型开关守护与类型断言里的格式一样,即 var.(Type),但是这里的type是一个关键字而非实际类型,用于表示任意类型。

类型开关的升级用法:

当我们解析JSON格式的数据,我们必须将数据转换成相对应的Go语言数据类型。这也可以通过GO标准库的json.Unmarshal()函数来实现。 我们想该函数传入一个只想结构体的指针,该结构体又与该json数据字段相匹配,那么该函数就会将JSON数据中对应的数据项填充到结构体的每一个字段。 但是如果我们事先不知道JSON数据的结构,那么就不能给json.Unmarshal()函数传入一个结构体。这种情况下,我们可以给该函数传入一个指向interfa{}的指针,这样json.Unmarshal()函数就会将其设置成引用一个map[string]interface{}类型值,其键位json字段的名字,值位对应的保存为interfa{}的值。

示例

func JsonUnkow() {
    MA := []byte(`{"name": "Massachusetts", "area": 27336, "water": 25.7, "senators":["John Kerry", "Scott Brown"]}`)
    var object interface{}
    if err := json.Unmarshal(MA, &object); err != nil {
        fmt.Println(err)
    } else {
        jsonObject := object.(map[string]interface{}) //将object类型转换成 map[string]interface{}
        fmt.Println(jsonObjectAsString(jsonObject))
    }
}

//将map中的interface{}类型值转换为实际类型的值
func jsonObjectAsString(jsonObject map[string]interface{}) string {
    var buffer bytes.Buffer
        buffer.WriteString("{")
    comma := ""
    for key, value := range jsonObject {
        buffer.WriteString(comma)
        switch value := value.(type) { //影子变量
        case nil:
            fmt.Fprintf(&buffer, "%q: null", key)
        case bool:
            fmt.Fprintf(&buffer, "%q: %t", key, value)
        case float64:
            fmt.Fprintf(&buffer, "%q: %f", key, value)
        case string:
            fmt.Fprintf(&buffer, "%q: %q", key, value)
        case []interface{}:
            fmt.Fprintf(&buffer, "%q: [", key)
            innerComma := ""
            for _, s := range value {
                if s, ok := s.(string); ok {
                    fmt.Fprintf(&buffer, "%s%q", innerComma, s)
                    innerComma = ", "
                }
            }
            buffer.WriteString("]")

        }
        comma = ", "
    }
    buffer.WriteString("}")
    return buffer.String()
}

上面的例子给出了如何反序列化一个其内部结构未知的原始json对象,如何创建和打印json对象的字符串表示。

输出打印

"{name": "Massachusetts", "area": 27336.000000, "water": 25.700000, "senators": ["John Kerry", "Scott Brown"]}

3、反射

反射的详细使用参考GO语言反射规则

4、日志

golang日志标准库只支持一些基本的日志操作,需要更丰富的日志操作,这里我们使用github.com/golang/glog这个第三方库。
glog只提供了少数几个选项,通过命令行控制,例如:

-log_dir: 日志文件保存目录

-alsologtostderr: 日志写入文件的同时,输出到stderr

-v:配置V输出的等级。

package main

import (
    "flag"
    "github.com/golang/glog"
)

func main() {
    //初始化glog命令行参数
    flag.Parse()    // 1

    glog.Info("This is a Info log")         // 2
    glog.Warning("This is a Warning log")
    glog.Error("This is a Error log")

    glog.V(1).Infoln("level 1")     // 3
    glog.V(2).Infoln("level 2")

    glog.Flush()    // 4
}

有几点说明:
1、高等级的日志会同时输出到比它等级低的文件中,例如error日志会同时输出到error文件,warning文件,info文件中,依次类推;

2、启动时,调用flag.Parse用来初始化glog的参数,例如xxx.exe -log_dir=”./”

3、程序退出时,需要调用glog.Flush(),将日志写入文件中。

4、V函数。默认的v选项为0,可以通过命令行设置v值。V函数的功能是,当V函数的参数高于glog的v值时,不会执行后续的Info函数,否则就执行。

参考文档:
GO语言程序设计(作者:Mark Summerfield 译者: 许式伟、吕桂华、徐立、何李石)5.2章节。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容