青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Fork me on GitHub
隨筆 - 215  文章 - 13  trackbacks - 0
<2018年10月>
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910


專注即時通訊及網游服務端編程
------------------------------------
Openresty 官方模塊
Openresty 標準模塊(Opm)
Openresty 三方模塊
------------------------------------
本博收藏大部分文章為轉載,并在文章開頭給出了原文出處,如有再轉,敬請保留相關信息,這是大家對原創作者勞動成果的自覺尊重!!如為您帶來不便,請于本博下留言,謝謝配合。

常用鏈接

留言簿(1)

隨筆分類

隨筆檔案

相冊

Awesome

Blog

Book

GitHub

Link

搜索

  •  

積分與排名

  • 積分 - 219795
  • 排名 - 117

最新評論

閱讀排行榜

http://blog.csdn.net/kai_ding/article/details/25948461


本文為轉載,原文地址:http://blog.go-china.org/22-type-assert

類型轉換在程序設計中都是不可避免的問題。當然有一些語言將這個過程給模糊了,大多數時候開發者并不需要去關注這方面的問題。但是golang中的類型匹配是很嚴格的,不同的類型之間通常需要手動轉換,編譯器不會代你去做這個事。我之所以說通常需要手動轉換,是因為interface類型作為一個特例,會有不同的處理方式。

golang中的所有類型都有自己的默認值,對此我做了個測試

$GOPATH/src

—-typeassert_test

——–main.Go

main.go的代碼如下:

package main

import (
    "fmt"
)

type myStruct struct {
    name   bool
    userid int64
}

var structZero myStruct
var intZero int
var int32Zero int32
var int64Zero int64
var uintZero uint
var uint8Zero uint8
var uint32Zero uint32
var uint64Zero uint64
var byteZero byte
var boolZero bool
var float32Zero float32
var float64Zero float64
var stringZero string
var funcZero func(int) int
var byteArrayZero [5]byte
var boolArrayZero [5]bool
var byteSliceZero []byte
var boolSliceZero []bool
var mapZero map[string]bool
var interfaceZero interface{}
var chanZero chan int
var pointerZero *int

func main() {
    fmt.Println("structZero: ", structZero)
    fmt.Println("intZero: ", intZero)
    fmt.Println("int32Zero: ", int32Zero)
    fmt.Println("int64Zero: ", int64Zero)
    fmt.Println("uintZero: ", uintZero)
    fmt.Println("uint8Zero: ", uint8Zero)
    fmt.Println("uint32Zero: ", uint32Zero)
    fmt.Println("uint64Zero: ", uint64Zero)
    fmt.Println("byteZero: ", byteZero)
    fmt.Println("boolZero: ", boolZero)
    fmt.Println("float32Zero: ", float32Zero)
    fmt.Println("float64Zero: ", float64Zero)
    fmt.Println("stringZero: ", stringZero)
    fmt.Println("funcZero: ", funcZero)
    fmt.Println("funcZero == nil?", funcZero == nil)
    fmt.Println("byteArrayZero: ", byteArrayZero)
    fmt.Println("boolArrayZero: ", boolArrayZero)
    fmt.Println("byteSliceZero: ", byteSliceZero)
    fmt.Println("byteSliceZero's len?", len(byteSliceZero))
    fmt.Println("byteSliceZero's cap?", cap(byteSliceZero))
    fmt.Println("byteSliceZero == nil?", byteSliceZero == nil)
    fmt.Println("boolSliceZero: ", boolSliceZero)
    fmt.Println("mapZero: ", mapZero)
    fmt.Println("mapZero's len?", len(mapZero))
    fmt.Println("mapZero == nil?", mapZero == nil)
    fmt.Println("interfaceZero: ", interfaceZero)
    fmt.Println("interfaceZero == nil?", interfaceZero == nil)
    fmt.Println("chanZero: ", chanZero)
    fmt.Println("chanZero == nil?", chanZero == nil)
    fmt.Println("pointerZero: ", pointerZero)
    fmt.Println("pointerZero == nil?", pointerZero == nil)
}
$ cd $GOPATH/src/typeassert_test
$ go build
$ ./typeassert_test

您可以清楚的了解到各種類型的默認值。如bool的默認值是false,string的默認值是空串,byte的默認值是0,數組的默認就是這個數組成員類型的默認值所組成的數組等等。然而您或許會發現在上面的例子中:map、interface、pointer、slice、func、chan的默認值和nil是相等的。關于nil可以和什么樣的類型做相等比較,您只需要知道nil可以賦值給哪些類型變量,那么就可以和哪些類型變量做相等比較。官方對此有明確的說明:http://pkg.golang.org/pkg/builtin/#Type,也可以看我的另一篇文章:[golang: 詳解interface和nil](http://my.oschina.net/goal/blog/194233)。所以現在您應該知道nil只能賦值給指針、channel、func、interface、map或slice類型的變量。如果您用int類型的變量跟nil做相等比較,panic會找上您。

對于字面量的值,編譯器會有一個隱式轉換。看下面的例子:

package main

import (
    "fmt"
)

func main() {
    var myInt int32     = 5
    var myFloat float64 = 0
    fmt.Println(myInt)
    fmt.Println(myFloat)
}

對于myInt變量,它存儲的就是int32類型的5;對于myFloat變量,它存儲的是int64類型的0。或許您可能會寫出這樣的代碼,但確實不是必須這么做的:

package main

import (
    "fmt"
)

func main() {
    var myInt int32     = int32(5)
    var myFloat float64 = float64(0)
    fmt.Println(myInt)
    fmt.Println(myFloat)
}

在C中,大多數類型轉換都是可以隱式進行的,比如:

#include <stdio.h>

int main(int argc, char **argv)
{
        int uid  = 12345;
        long gid = uid;
        printf("uid=%d, gid=%d\n", uid, gid);
        return 0;
}

但是在golang中,您不能這么做。有個類似的例子:

package main

import (
    "fmt"
)

func main() {
    var uid int32 = 12345
    var gid int64 = int64(uid)
    fmt.Printf("uid=%d, gid=%d\n", uid, gid)
}

很顯然,將uid賦值給gid之前,需要將uid強制轉換成int64類型,否則會panic。golang中的類型區分靜態類型和底層類型。您可以用type關鍵字定義自己的類型,這樣做的好處是可以語義化自己的代碼,方便理解和閱讀。

package main

import (
    "fmt"
)

type MyInt32 int32

func main() {
    var uid int32   = 12345
    var gid MyInt32 = MyInt32(uid)
    fmt.Printf("uid=%d, gid=%d\n", uid, gid)
}

在上面的代碼中,定義了一個新的類型MyInt32。對于類型MyInt32來說,MyInt32是它的靜態類型,int32是它的底層類型。即使兩個類型的底層類型相同,在相互賦值時還是需要強制類型轉換的。可以用reflect包中的Kind方法來獲取相應類型的底層類型。

對于類型轉換的截斷問題,為了問題的簡單化,這里只考慮具有相同底層類型之間的類型轉換。小類型(這里指存儲空間)向大類型轉換時,通常都是安全的。下面是一個大類型向小類型轉換的示例:

package main

import (
    "fmt"
)

func main() {
    var gid int32 = 0x12345678
    var uid int8  = int8(gid)
    fmt.Printf("uid=0x%02x, gid=0x%02x\n", uid, gid)
}

在上面的代碼中,gid為int32類型,也即占4個字節空間(在內存中占有4個存儲單元),因此這4個存儲單元的值分別是:0x12, 0x34, 0x56, 0x78。但事實不總是如此,這跟cpu架構有關。在內存中的存儲方式分為兩種:大端序和小端序。大端序的存儲方式是高位字節存儲在低地址上;小端序的存儲方式是高位字節存儲在高地址上。本人的機器是按小端序來存儲的,所以gid在我的內存上的存儲序列是這樣的:0x78, 0x56, 0x34, 0x12。如果您的機器是按大端序來存儲,則gid的存儲序列剛好反過來:0x12, 0x34, 0x56, 0x78。對于強制轉換后的uid,肯定是產生了截斷行為。因為uid只占1個字節,轉換后的結果必然會丟棄掉多余的3個字節。截斷的規則是:保留低地址上的數據,丟棄多余的高地址上的數據。來看下測試結果:

$ cd $GOPATH/src/typeassert_test
$ go build
$ ./typeassert_test
uid=0x78, gid=0x12345678

如果您的輸出結果是:

uid=0x12, gid=0x12345678

那么請不要驚訝,因為您的機器是屬于大端序存儲。

其實很容易根據上面所說的知識來判斷是屬于大端序或小端序:

package main

import (
    "fmt"
)

func IsBigEndian() bool {
    var i int32 = 0x12345678
    var b byte  = byte(i)
    if b == 0x12 {
        return true
    }

    return false
}

func main() {
    if IsBigEndian() {
        fmt.Println("大端序")
    } else {
        fmt.Println("小端序")
    }
}

接口的轉換遵循以下規則:

普通類型向接口類型的轉換是隱式的。

接口類型向普通類型轉換需要類型斷言。

普通類型向接口類型轉換的例子隨處可見,例如:

package main

import (
    "fmt"
)

func main() {
    var val interface{} = "hello"
    fmt.Println(val)
    val = []byte{'a', 'b', 'c'}
    fmt.Println(val)
}

正如您所預料的,”hello”作為string類型存儲在interface{}類型的變量val中,[]byte{‘a’, ‘b’, ‘c’}作為slice存儲在interface{}類型的變量val中。這個過程是隱式的,是編譯期確定的。

接口類型向普通類型轉換有兩種方式:Comma-ok斷言和switch測試。任何實現了接口I的類型都可以賦值給這個接口類型變量。由于interface{}包含了0個方法,所以任何類型都實現了interface{}接口,這就是為什么可以將任意類型值賦值給interface{}類型的變量,包括nil。還有一個要注意的就是接口的實現問題,*T包含了定義在T和*T上的所有方法,而T只包含定義在T上的方法。我們來看一個例子:

package main

import (
    "fmt"
)

// 演講者接口
type Speaker interface {
    // 說
    Say(string)
    // 聽
    Listen(string) string
    // 打斷、插嘴
    Interrupt(string)
}

// 王蘭講師
type WangLan struct {
    msg string
}

func (this *WangLan) Say(msg string) {
    fmt.Printf("王蘭說:%s\n", msg)
}

func (this *WangLan) Listen(msg string) string {
    this.msg = msg
    return msg
}

func (this *WangLan) Interrupt(msg string) {
    this.Say(msg)
}

// 江婁講師
type JiangLou struct {
    msg string
}

func (this *JiangLou) Say(msg string) {
    fmt.Printf("江婁說:%s\n", msg)
}

func (this *JiangLou) Listen(msg string) string {
    this.msg = msg
    return msg
}

func (this *JiangLou) Interrupt(msg string) {
    this.Say(msg)
}

func main() {
    wl := &WangLan{}
    jl := &JiangLou{}

    var person Speaker
    person = wl
    person.Say("Hello World!")
    person = jl
    person.Say("Good Luck!")
}

Speaker接口有兩個實現WangLan類型和JiangLou類型。但是具體到實例來說,變量wl和變量jl只有是對應實例的指針類型才真正能被Speaker接口變量所持有。這是因為WangLan類型和JiangLou類型所有對Speaker接口的實現都是在*T上。這就是上例中person能夠持有wl和jl的原因(不明白的可以看看我的其他相關博客)。

想象一下Java的泛型(很可惜golang不支持泛型),java在支持泛型之前需要手動裝箱和拆箱。由于golang能將不同的類型存入到接口類型的變量中,使得問題變得更加復雜。所以有時候我們不得不面臨這樣一個問題:我們究竟往接口存入的是什么樣的類型?有沒有辦法反向查詢?答案是肯定的。

Comma-ok斷言的語法是:value, ok := element.(T)。element必須是接口類型的變量,T是普通類型。如果斷言失敗,ok為false,否則ok為true并且value為變量的值。來看個例子:

package main

import (
    "fmt"
)

type Html []interface{}

func main() {
    html := make(Html, 5)
    html[0] = "div"
    html[1] = "span"
    html[2] = []byte("script")
    html[3] = "style"
    html[4] = "head"
    for index, element := range html {
        if value, ok := element.(string); ok {
            fmt.Printf("html[%d] is a string and its value is %s\n", index, value)
        } else if value, ok := element.([]byte); ok {
            fmt.Printf("html[%d] is a []byte and its value is %s\n", index, string(value))
        }
    }
}

其實Comma-ok斷言還支持另一種簡化使用的方式:value := element.(T)。但這種方式不建議使用,因為一旦element.(T)斷言失敗,則會產生運行時錯誤。如:

package main

import (
    "fmt"
)

func main() {
    var val interface{} = "good"
    fmt.Println(val.(string))
    // fmt.Println(val.(int))
}

以上的代碼中被注釋的那一行會運行時錯誤。這是因為val實際存儲的是string類型,因此斷言失敗。

還有一種轉換方式是switch測試。既然稱之為switch測試,也就是說這種轉換方式只能出現在switch語句中。可以很輕松的將剛才用Comma-ok斷言的例子換成由switch測試來實現:

package main

import (
    "fmt"
)

type Html []interface{}

func main() {
    html := make(Html, 5)
    html[0] = "div"
    html[1] = "span"
    html[2] = []byte("script")
    html[3] = "style"
    html[4] = "head"
    for index, element := range html {
        switch value := element.(type) {
        case string:
            fmt.Printf("html[%d] is a string and its value is %s\n", index, value)
        case []byte:
            fmt.Printf("html[%d] is a []byte and its value is %s\n", index, string(value))
        case int:
            fmt.Printf("error type\n")
        default:
            fmt.Printf("unknown type\n")
        }
    }
}
$ cd $GOPATH/src/typeassert_test
$ go build
$ ./typeassert_test

posted on 2017-05-04 10:30 思月行云 閱讀(257) 評論(0)  編輯 收藏 引用 所屬分類: Golang
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            99精品99久久久久久宅男| 亚洲国产午夜| 日韩一区二区精品视频| 欧美专区福利在线| 欧美在线黄色| 久久精品国产亚洲一区二区三区 | 久久久99久久精品女同性| 一区二区三区日韩精品| 99国产成+人+综合+亚洲欧美| 日韩一级大片| 午夜视频在线观看一区二区三区 | 韩国av一区二区| 一区二区三区自拍| 一本一道久久综合狠狠老精东影业| 亚洲国产日韩一级| 亚洲免费观看高清在线观看| 在线播放中文字幕一区| 91久久精品国产91性色tv| 亚洲精品乱码久久久久久日本蜜臀 | 欧美日韩在线播放一区| 欧美午夜精品久久久久免费视| 国产精品高精视频免费| 国产女主播在线一区二区| 国产亚洲精品久久久久久| 亚洲福利一区| 性色av一区二区三区| 久久男女视频| 99国产精品99久久久久久| 亚洲深夜福利在线| 久久综合婷婷| 国产麻豆精品视频| 99v久久综合狠狠综合久久| 亚洲精品三级| 美女精品一区| 国产欧美日韩另类一区| 91久久久在线| 久久久亚洲人| 亚洲性图久久| 欧美日韩中文字幕综合视频| 国产精品色婷婷| 一本色道久久综合狠狠躁篇怎么玩| 99视频+国产日韩欧美| 久久精品国产综合精品| 亚洲精品视频在线观看免费| 亚洲欧美久久久久一区二区三区| 久久综合精品国产一区二区三区| 国产精品久久婷婷六月丁香| 在线观看国产日韩| 久久亚洲欧美| 亚洲欧美日韩中文视频| 欧美激情a∨在线视频播放| 国产综合精品一区| 久久精品国产一区二区三区免费看| 亚洲福利国产| 欧美国产国产综合| 日韩视频免费观看| 亚洲国产福利在线| 美乳少妇欧美精品| 尤物yw午夜国产精品视频| 欧美在线观看视频| 亚洲无亚洲人成网站77777| 欧美日韩国内| 在线视频日韩| 亚洲精品裸体| 欧美日本一道本| 一区二区三区波多野结衣在线观看| 美女精品自拍一二三四| 夜夜精品视频一区二区| 欧美成人激情在线| 久久成人18免费观看| 国产一区二区日韩| 久久精品国产成人| 久久精品国产一区二区三| 国产亚洲欧美一级| 玖玖玖免费嫩草在线影院一区| 香蕉乱码成人久久天堂爱免费| 国产精品推荐精品| 久久看片网站| 免费观看欧美在线视频的网站| 在线观看成人小视频| 久久久噜噜噜久久人人看| 午夜精品福利一区二区蜜股av| 国产精品五月天| 久久精品国产免费观看| 亚洲免费婷婷| 国产一区二区主播在线| 久久青草久久| 美女视频黄a大片欧美| 亚洲高清自拍| 日韩性生活视频| 欧美午夜片在线观看| 亚洲一区二区三区在线| 亚洲小视频在线观看| 欧美视频第二页| 欧美一区二区三区视频免费| av成人免费在线观看| 国产精品视频| 欧美国产日产韩国视频| 欧美日韩a区| 欧美一区二区三区精品| 久久麻豆一区二区| 亚洲影院高清在线| 久久精彩免费视频| 亚洲精品一区二区在线观看| 亚洲精品在线看| 国产日韩av在线播放| 玖玖综合伊人| 国产精品二区在线| 亚洲国产欧美久久| 国产欧美日韩伦理| 99视频精品在线| 伊人久久亚洲美女图片| 一区二区三区不卡视频在线观看| 国产女主播在线一区二区| 欧美国产亚洲精品久久久8v| 亚洲一线二线三线久久久| 欧美一区二区视频在线| 99re热精品| 猛男gaygay欧美视频| 亚洲午夜精品17c| 欧美成人午夜激情| 久久视频在线看| 国产欧美日韩综合精品二区| 久久另类ts人妖一区二区| 欧美日本在线视频| 老司机精品视频网站| 欧美色道久久88综合亚洲精品| 亚洲一区二区三区激情| 欧美大片在线看免费观看| 久久精品国产99| 欧美午夜久久| 亚洲高清影视| 91久久精品国产91性色tv| 久久精品网址| 久久精品成人一区二区三区| 欧美精品久久久久久久久老牛影院 | 狠狠色狠狠色综合人人| 欧美高清在线| 亚洲高清久久网| 久久一区二区三区国产精品| 在线视频一区观看| 欧美在线视频播放| 国产乱子伦一区二区三区国色天香| 免费永久网站黄欧美| 国产精品一二三四| 亚洲精品一区二区三区婷婷月| 在线看片一区| 久久国产精品久久久| 久久国产视频网| 国产精品网站在线| 亚洲欧美中文日韩v在线观看| 亚洲精品九九| 欧美激情一区二区三区蜜桃视频| 亚洲高清视频在线观看| 亚洲巨乳在线| 国产精品看片你懂得| 一本色道久久综合精品竹菊| 亚洲美女中文字幕| 欧美久久电影| 亚洲欧美国产制服动漫| 午夜在线精品偷拍| 国内精品久久久久久久97牛牛| 香蕉久久一区二区不卡无毒影院| 久久久久久一区二区三区| 韩国亚洲精品| 欧美日韩在线电影| 欧美在线观看视频| 最近中文字幕日韩精品| 亚洲永久免费精品| 一色屋精品视频在线观看网站| 美女精品一区| 亚洲免费影视| 亚洲日韩欧美视频| 欧美在线免费看| 亚洲三级免费| 国产一区二区三区成人欧美日韩在线观看 | 久久久久国产精品麻豆ai换脸| 欧美激情麻豆| 欧美一级视频精品观看| 一本色道久久综合狠狠躁的推荐| 一区二区三区黄色| 韩日午夜在线资源一区二区| 午夜精品视频在线| 亚洲第一区在线| 久久久综合精品| 亚洲午夜电影在线观看| 国产伪娘ts一区| 欧美喷水视频| 久久xxxx精品视频| 亚洲精品在线视频观看| 久久蜜臀精品av| 亚洲在线国产日韩欧美| 国产深夜精品| 国产精品国产三级国产专区53| 久久精品99国产精品酒店日本| 亚洲福利视频二区| 久久免费黄色| 欧美专区亚洲专区| 亚洲影视在线| 亚洲视频欧美在线|