色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

關于go中接口類型的表示方法

馬哥Linux運維 ? 來源:cnblogs ? 2024-04-28 10:13 ? 次閱讀

類型和接口

因為映射建設在類型的基礎之上,首先我們對類型進行全新的介紹。

go是一個靜態性語言,每個變量都有靜態的類型,因此每個變量在編譯階段中有明確的變量類型,比如像:int、float32、MyType。。。

比如:

type MyInt int
var i int
var j MyInt

變量i的類型為int,變量j的類型為MyInt,變量i、j具有確定的類型,雖然i、j的潛在類型是一樣的,但是在沒有轉換的情況下他們之間不能相互賦值。

在類型中有重要的一類為接口類型(interface),接口類型為一系列方法的集合。一個接口型變量可以存儲接口方法中聲明的任何具體的值。像io.Reader和io.Writer是一個很好的例子,這兩個接口在io包中定義。

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

type Writer interface{
    Writer(p []byte)(n int,er error)
}

任何聲明為io.Reader或者io.Writer類型的變量都可以使用Read或者Writer 方法。也就意味著io.Reader類型的變量可以賦值任何有Read方法的的變量。

var r io.Reader
r = os.Stdin
r = bufio.NewReader(r)
r = new(bytes.Buffer)

無論變量r被賦值什么類型的值,變量r的類型依舊是io.Reader。go語言是靜態類型語言,并且r的類型永遠是io.Reader。

在接口類型中有一個重要的極端接口類型--空接口。
interface{}
他代表一個空的方法集合并且可以被賦值為任何值,因為任何一個變量都有0個或者多個方法。
有一種錯誤的說法是go的接口類型是動態定義的,其實在go中他們是靜態定義的,一個接口類型的變量總是有著相同類型的類型,盡管在運行過程中存儲在接口類型變量的值具有不同的類型,但是接口類型的變量永遠是靜態的類型。

接口的表示方法

關于go中接口類型的表示方法Russ Cox大神在一篇博客中已經詳細介紹[blog//research.swtch.com/2009/12/go-data-structures-interfaces.html]
一個接口類型的變量存儲一對信息:具體值,值的類型描述。更具體一點是,值是實現接口的底層具體數據項,類型是數據項類型的完整描述。

舉個例子:

var r io.Reader
tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
if err != nil {
    return nil, err
}
r = tty

變量r包含兩個數據項:值(tty),類型(os.File)。注意os.File實現的方法不僅僅是Read,即使接口類型僅包含Read方法,但是值(tty)卻用于其完整的類型信息,因此我們可以按照如下方法調用

var w io.Writer
w = r.(io.Writer)

這條語句是一個斷言語句,斷言的意思是變量r中的數據項聲明為io.Writer,因為我們可以將r賦值給w。執行完這條語句以后,變量w將和r一樣包含值(tty)、類型(*os.File)。即使具體值可能包含很多方法,但是接口的靜態類型決定什么方法可以通過接口型變量調用。

同樣我們可以

var empty interface{}
empty = w

這個接口型變量同樣包含一個數據對(tty,*os.File)。空接口可以接受任何類型的變量,并且包含我們可能用到的關于這個變量的所有信息。在這里我們不需要斷言是因為w變量滿足于空接口。在上一個從Reader向Writer移動數據的例子中,我們需要類型斷言,因為Reader接口中不包含Writer方法

切記接口的數據對中的內容只能來自于(value , concrete type)而不能是(value, interface type),也就是接口類型不能接受接口類型的變量。

1.從接口類型到映射對象

在最底層,映射是對存儲在接口內部數據對(值、類型)的解釋機制。首先我們需要知道在reflect包中的兩種類型Type和Value,這兩種類型提供了對接口變量內部內容的訪問,同時reflect.TypeOf和reflect.ValueOf兩個方法檢索接口類型的變量。

首先我們開始TypeOf

package main

import (
    "fmt"
    "reflect"
)

func main() {
    var f float64 = 13.4
    fmt.Println(reflect.TypeOf(f))
    fmt.Println("Hello, playground")
}

結果

float64
Hello, playground

我們可以會感到奇怪這里沒有接口呀?因為在程序中我們可以得知f的變量類型應為float32,不應該是什么變量類型。但是我們在golang源碼中我們得知,reflect.TypeOf包含一個空接口類型的變量.

func TypeOf(i interface{})Type
當我們在調用reflect.TypeOf方法時,x首先存儲在一個空的接口中,然后再作為一個參數傳送到reflect.TypeOf方法中,然后該方法解壓這個空的接口得到類型信息。
同樣reflect.ValueOf方法,得到值。

var f float64 = 13.4

    fmt.Println(reflect.ValueOf(f))

結果

13.4

reflect.Type和reflec.Value有許多方法讓我們檢查和修改它們。一個比較重要的方法是Value有一個能夠返回reflect.Value的類型的方法Type。另外一個比較重要的是Type和Value都提供一個Kind方法,該方法能夠返回存儲數據項的字長(Uini,Floatr64,Slice等等)。同樣Value方法也提供一些叫做Int、Float的方法讓我們修改存儲在內部的值。

    var f float64 = 13.44444
    v := reflect.ValueOf(f)
    fmt.Println(v)
    fmt.Println(v.Type())
    fmt.Println(v.Kind())
    fmt.Println(v.Float())

結果

13.444444444444445
float64
float64
13.444444444444445

同時有像SetInt、SetFloat之類的方法,但是我們必須謹慎的使用它們。

反射機制有兩個重要的性質。首先,為了保證接口的簡潔行,getter和setter兩個方法是可以接受最大類型值的賦值,比如int64可以接受任何符號整數。所以值的Int方法會返回一個int64類型的值,SetInt接受int64類型的值,因此它可能轉化為所涉及的實際類型。

var x uint8 = 'x'
v := reflect.ValueOf(x)
fmt.Println("type:", v.Type())                            // uint8.
fmt.Println("kind is uint8: ", v.Kind() == reflect.Uint8) // true.
x = uint8(v.Uint())                                       // v.Uint returns a uint64.

第二個特性:接口保存了數據項底層類型,而不是靜態的類型,如果一個接口包含用戶定義的整數類型的值,比如

type MyInt int
var x MyInt = 7
v := reflect.ValueOf(x)

則v的Kind方法調用仍然返回的是reflect.Int,盡管x的靜態類型是MyInt。也可以說,Kind`不會像Type`一樣將MyInt和int當作兩種類型來對待。

2.從映射對象到接口的值

像物理映射一樣,Go中的映射也有其自身的相反性。

通過利用Interface的方法我們可以將interface.Value恢復至接口類型,實際上這個方法將type和value信息包裝至interface類型并且返回該值。

// Interface returns v's value as an interface{}.
func (v Value) Interface() interface{}

因此我們可以說

y := v.Interface().(float64) // y will have type float64.
fmt.Println(y)

打印float64類型的值,其實是接口類型變量v的映射。

或者我們可以這樣做,fmt.Println,fmt.Printf等函數的參數盡管是空的接口類型也能運行,在fmt包里面解析出type和value的方法和我們上面的例子相似。因此所有正確打印reflect.Value的方法都試通過interface的方法將值傳遞給格式化打印函數。

fmt.Println(v.Interface())

(為什么不是fmt.Println(v)?因為通過v是reflect.Value類型.)因為我們的值底層是float64類型,因此我們甚至可以浮點類型的格式打印.

fmt.Printf("value is %7.1e
", v.Interface())

結果是

3.4e+00

因此我們不用類型斷言v.Interface{}到float64類型。因為接口類型內部保存著值的信息,Printf函數能夠恢復這些信息。

簡單的說Interface是ValueOf的反操作,除非這個值總是靜態的Interface類型。

改變接口對象,他的值必須是可改變的

第三法則比較微妙并且容易混淆,但是如果從第一準則開始看的話,那么還是比較容易理解的。

這是一條錯誤的語句,但是這個錯誤值得我們研究

var x float64 = 3.4
v := reflect.ValueOf(x)
v.SetFloat(7.1) // Error: will panic.

如果你運行這條語句則會有下面的報錯信息

panic: reflect.Value.SetFloat using unaddressable value

因為變量v是不可更改的,所以提示值7.1是不可尋址的。可賦值是value的一個特性,但是并不是所以的value都具有這個特性。

CanSet方法返回該值是否是可以改變的,比如

var x float64 = 3.4
v := reflect.ValueOf(x)
fmt.Println("settability of v:", v.CanSet())

結果是

settability of v: false

如果在不可以賦值的變量上進行賦值,就回引起錯誤。但是到底是什么才是可以賦值的呢?

可賦值的有點像是可尋址的,但是會更嚴格。映射對象可以更改存儲值的特性可以用來創建新的映射對象。映射對象包含原始的數據項是決定映射對象可賦值的關鍵。當下面代碼運行時

var x float64 = 3.4
v := reflect.ValueOf(x)

只是將x的拷貝到reflect.ValueOf,因此reflect.ValueOf的返回值是x的復制項,而不是x本身。假如下面這條語句可以正常運行

v.SetFloat(5.4)

盡管v看起來是由x創建的,但是并不會更新x的值,因為這條語句會更新x拷貝值的值,但是并不影響x本身,因此可更改的這一特性就是為了避免這種操作。

雖然這看起來很古怪,但其實這是一種很熟悉的操作。比如我們將x值賦值給一個方法

f(x)

我們本身不想修改x的值,因為傳入的只是x值的拷貝,但是如果我們想修改x的值,那么我們需要傳送x的地址(也就是x的指針)

f(&x)

這種操作是簡單明了的,其實對于映射也是一樣的。如果我們想通過映射修改x的值,那么我們需要傳送x的指針。比如

var x float64 = 3.4
p := reflect.ValueOf(&x) // Note: take the address of x.
fmt.Println("type of p:", p.Type())
fmt.Println("settability of p:", p.CanSet())

結果

type of p: *float64
settability of p: false

映射對象p仍然是不可修改的,但是其實我們并不想修改p,而是*p。為了得到指針的指向,我們需要使用Elem()方法,該方法將會指向*p的值,并且將其保存到映射變量中

v := p.Elem()
fmt.Println("settability of v:", v.CanSet())

結果為

settability of v: true

現在v是一個可修改的映射對象。并且v代表x,因此我們可以使用v.SetFloat()來修改x的值。

v.SetFloat(7.1)
fmt.Println(v.Interface())
fmt.Println(x)

輸出結果為

7.1
7.1

映射是比較難理解的,盡管我們通過映射的Values``Types隱藏了到底發生了什么操作。我們只需要記住如果想改變它的值,那在調用ValuesOf方法時應該使用指向它的指針。

Struct

在上一個例子中v并不是指向自身的指針,而是通過其他方式產生的。還有一種常用的操作就是修改結構體的某個字段,只要我們知道了結構體的地址,我們就能修改它的字段。

這有一個修改結構體變量t的例子。因為我們要修改結構體的字段,所以我們使用結構體指針創建結構體對象。我們使用typeOfT代表t的數據類型,并通過NumField方法迭代結構體的字段。主意:我們只是提取出結構體類型字段的的名字,而他們的reflect.Value對象。

type T struct {
    A int
    B string
}
t := T{23, "skidoo"}
s := reflect.ValueOf(&t).Elem()
typeOfT := s.Type()
for i := 0; i < s.NumField(); i++ {
    f := s.Field(i)
    fmt.Printf("%d: %s %s = %v
", i,
        typeOfT.Field(i).Name, f.Type(), f.Interface())
}

輸出結果是

0: A int = 23
1: B string = skidoo

值得注意的是只有可導出的字段才能使可修改的。

因為s包含一個可修改的映射對象,所以我們可以修改結構體的字段

s.Field(0).SetInt(77)
s.Field(1).SetString("Sunset Strip")
fmt.Println("t is now", t)

結果為

t is now {77 Sunset Strip}

如果s是通過t創建而不是&t,那么SetInt和SetString方法都會出錯,因為t的字段是不可以修改的。

審核編輯:黃飛

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 接口
    +關注

    關注

    33

    文章

    8611

    瀏覽量

    151229
  • Go
    Go
    +關注

    關注

    0

    文章

    43

    瀏覽量

    12256
  • 數據類型
    +關注

    關注

    0

    文章

    236

    瀏覽量

    13624

原文標題:GO接口三個特性

文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    硬盤接口類型

    硬盤接口類型              接口類型是指該SCSI硬盤與電腦主機之間的連接方式或類型。與IDE硬盤相比,SCSI硬盤
    發表于 12-17 14:17 ?2735次閱讀

    顯卡總線接口類型

    顯卡總線接口類型            總線接口類型是指顯卡
    發表于 12-25 10:28 ?8970次閱讀

    內存接口類型有哪些?

    內存接口類型有哪些?       接口類型是根據內存條金手指上導電觸片的數量來劃分的,金手指上的導電觸片也習慣稱為針腳數(Pin)。
    發表于 12-25 14:19 ?5476次閱讀

    聲卡接口類型

     聲卡接口類型   
    發表于 12-26 11:00 ?2619次閱讀

    聲卡接口類型有哪些?

    聲卡接口類型有哪些?        ●線型輸入接口,標記
    發表于 12-26 11:17 ?1.1w次閱讀

    鍵盤接口類型

    鍵盤接口類型 接口類型是指鍵盤與電腦主機之間相連接的接口方式或類型。目前市面上常見的鍵盤接口有三種:老式AT
    發表于 12-28 11:07 ?2356次閱讀

    鼠標接口類型

    鼠標接口類型 接口類型是指鼠標與電腦主機之間相連接的接口方式或類型。目前常見的鼠標接口有串口,PS/2和USB三種
    發表于 12-28 11:26 ?2169次閱讀

    條碼打印機的接口類型

    條碼打印機的接口類型              接口類型指的是條
    發表于 12-30 11:53 ?1638次閱讀

    錄音電話的接口類型

    錄音電話的接口類型              接口類型即錄音電話與
    發表于 12-31 14:45 ?1184次閱讀

    網橋接口類型

    網橋接口類型 網橋典型的接口類型有以太網接口,E1接口、配置接口等。     1.以太網
    發表于 01-06 13:38 ?2580次閱讀

    磁帶機的接口類型

    磁帶機的接口類型  目前磁帶機的接口類型有LPT接口(line print terminal,俗稱并口)、EIDE(Enhanced IDE 增強型IDE)接口、SCSI(
    發表于 01-09 09:01 ?2653次閱讀

    SCSI硬盤的接口類型

    SCSI硬盤的接口類型              接口類型是指該SCSI硬盤與電腦主機之間的連接方式或類型。與IDE硬盤相比,S
    發表于 01-09 11:44 ?4270次閱讀

    讀卡器的接口類型

    讀卡器的接口類型              接口類型是指讀卡器與電腦主機之間的連接方式和類型。目前讀卡器都是采用USB
    發表于 01-09 15:06 ?4403次閱讀

    收發器的接口類型

    收發器的接口類型 收發器典型的接口類型有以太網接口,E1接口、串行接口(RS232)、SC/ST接
    發表于 01-08 14:15 ?1580次閱讀

    ssd硬盤的接口類型

    本視頻主要詳細介紹了ssd硬盤的接口類型,分別是AHCI協議和NVMe協議的接口類型,具體的有SATA接口、mSATA接口、M.2接口(NG
    的頭像 發表于 03-10 09:16 ?3w次閱讀
    主站蜘蛛池模板: 高挑人妻无奈张开腿| 992交通广播| 中文字幕人成乱码熟女APP| 法国剧丝袜情版h级在线电影| 美女张开腿让男生桶动态图 | 秋霞网在线伦理免费| 97免费观看视频| 免费人妻AV无码专区五月| 综合久久久久久久综合网| 巨污全肉np一女多男| 51精品少妇人妻AV一区二区 | www.亚洲天堂| 人妻无码AV中文系列| 成年人视频在线免费观看| 日本三级按摩推拿按摩| 成人在线免费视频观看| 丝瓜影院观看免费高清国际观察| 国产成人免费片在线观看| 受坐在攻腿上H道具PLAY| 国产精品女上位在线观看| 亚洲AV天堂无码麻豆电影| 精品亚洲午夜久久久久| 诱咪视频免费| 暖暖日本免费播放| 成人国产亚洲精品A区天堂蜜臀| 三叶草成人| 国产中文视频| 国产又粗又猛又爽又黄的免费视频| 午夜射精日本三级| 久久91精品国产91久久户| 在线免费观看a视频| 欧美阿v在线天堂| 国产成人久视频免费| 亚洲精品久久99蜜芽尤物TV| 久久综合色视频| 成人国产亚洲欧美成人综合网 | 日韩欧美一区二区中文字幕| 国产一区91| 2224x最新网站| 色偷偷777| 久久久精品久久|