女人自慰AV免费观看内涵网,日韩国产剧情在线观看网址,神马电影网特片网,最新一级电影欧美,在线观看亚洲欧美日韩,黄色视频在线播放免费观看,ABO涨奶期羡澄,第一导航fulione,美女主播操b

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

GOLANG接口三個(gè)特性介紹

馬哥Linux運(yùn)維 ? 來(lái)源:cnblogs ? 2024-04-16 11:40 ? 次閱讀

類(lèi)型和接口

因?yàn)橛成浣ㄔO(shè)在類(lèi)型的基礎(chǔ)之上,首先我們對(duì)類(lèi)型進(jìn)行全新的介紹。

go是一個(gè)靜態(tài)性語(yǔ)言,每個(gè)變量都有靜態(tài)的類(lèi)型,因此每個(gè)變量在編譯階段中有明確的變量類(lèi)型,比如像:int、float32、MyType。。。

比如:

type MyInt int
var i int
var j MyInt

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

在類(lèi)型中有重要的一類(lèi)為接口類(lèi)型(interface),接口類(lèi)型為一系列方法的集合。一個(gè)接口型變量可以存儲(chǔ)接口方法中聲明的任何具體的值。像io.Reader和io.Writer是一個(gè)很好的例子,這兩個(gè)接口在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類(lèi)型的變量都可以使用Read或者Writer 方法。也就意味著io.Reader類(lèi)型的變量可以賦值任何有Read方法的的變量。

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

無(wú)論變量r被賦值什么類(lèi)型的值,變量r的類(lèi)型依舊是io.Reader。go語(yǔ)言是靜態(tài)類(lèi)型語(yǔ)言,并且r的類(lèi)型永遠(yuǎn)是io.Reader。

在接口類(lèi)型中有一個(gè)重要的極端接口類(lèi)型--空接口。
interface{}
他代表一個(gè)空的方法集合并且可以被賦值為任何值,因?yàn)槿魏我粋€(gè)變量都有0個(gè)或者多個(gè)方法。
有一種錯(cuò)誤的說(shuō)法是go的接口類(lèi)型是動(dòng)態(tài)定義的,其實(shí)在go中他們是靜態(tài)定義的,一個(gè)接口類(lèi)型的變量總是有著相同類(lèi)型的類(lèi)型,盡管在運(yùn)行過(guò)程中存儲(chǔ)在接口類(lèi)型變量的值具有不同的類(lèi)型,但是接口類(lèi)型的變量永遠(yuǎn)是靜態(tài)的類(lèi)型。

接口的表示方法

關(guān)于go中接口類(lèi)型的表示方法Russ Cox大神在一篇博客中已經(jīng)詳細(xì)介紹[blog//research.swtch.com/2009/12/go-data-structures-interfaces.html]
一個(gè)接口類(lèi)型的變量存儲(chǔ)一對(duì)信息:具體值,值的類(lèi)型描述。更具體一點(diǎn)是,值是實(shí)現(xiàn)接口的底層具體數(shù)據(jù)項(xiàng),類(lèi)型是數(shù)據(jù)項(xiàng)類(lèi)型的完整描述。

舉個(gè)例子:

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

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

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

這條語(yǔ)句是一個(gè)斷言語(yǔ)句,斷言的意思是變量r中的數(shù)據(jù)項(xiàng)聲明為io.Writer,因?yàn)槲覀兛梢詫賦值給w。執(zhí)行完這條語(yǔ)句以后,變量w將和r一樣包含值(tty)、類(lèi)型(*os.File)。即使具體值可能包含很多方法,但是接口的靜態(tài)類(lèi)型決定什么方法可以通過(guò)接口型變量調(diào)用。

同樣我們可以

var empty interface{}
empty = w

這個(gè)接口型變量同樣包含一個(gè)數(shù)據(jù)對(duì)(tty,*os.File)。空接口可以接受任何類(lèi)型的變量,并且包含我們可能用到的關(guān)于這個(gè)變量的所有信息。在這里我們不需要斷言是因?yàn)閣變量滿(mǎn)足于空接口。在上一個(gè)從Reader向Writer移動(dòng)數(shù)據(jù)的例子中,我們需要類(lèi)型斷言,因?yàn)镽eader接口中不包含Writer方法

切記接口的數(shù)據(jù)對(duì)中的內(nèi)容只能來(lái)自于(value , concrete type)而不能是(value, interface type),也就是接口類(lèi)型不能接受接口類(lèi)型的變量。

1.從接口類(lèi)型到映射對(duì)象

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

首先我們開(kāi)始TypeOf

package main

import (
    "fmt"
    "reflect"
)

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

結(jié)果

float64
Hello, playground

我們可以會(huì)感到奇怪這里沒(méi)有接口呀?因?yàn)樵诔绦蛑形覀兛梢缘弥猣的變量類(lèi)型應(yīng)為float32,不應(yīng)該是什么變量類(lèi)型。但是我們?cè)趃olang源碼中我們得知,reflect.TypeOf包含一個(gè)空接口類(lèi)型的變量.

func TypeOf(i interface{})Type

當(dāng)我們?cè)谡{(diào)用reflect.TypeOf方法時(shí),x首先存儲(chǔ)在一個(gè)空的接口中,然后再作為一個(gè)參數(shù)傳送到reflect.TypeOf方法中,然后該方法解壓這個(gè)空的接口得到類(lèi)型信息。

同樣reflect.ValueOf方法,得到值。

var f float64 = 13.4

    fmt.Println(reflect.ValueOf(f))

結(jié)果

13.4

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

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

結(jié)果

13.444444444444445
float64
float64
13.444444444444445

同時(shí)有像SetInt、SetFloat之類(lèi)的方法,但是我們必須謹(jǐn)慎的使用它們。

反射機(jī)制有兩個(gè)重要的性質(zhì)。首先,為了保證接口的簡(jiǎn)潔行,getter和setter兩個(gè)方法是可以接受最大類(lèi)型值的賦值,比如int64可以接受任何符號(hào)整數(shù)。所以值的Int方法會(huì)返回一個(gè)int64類(lèi)型的值,SetInt接受int64類(lèi)型的值,因此它可能轉(zhuǎn)化為所涉及的實(shí)際類(lèi)型。

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.

第二個(gè)特性:接口保存了數(shù)據(jù)項(xiàng)底層類(lèi)型,而不是靜態(tài)的類(lèi)型,如果一個(gè)接口包含用戶(hù)定義的整數(shù)類(lèi)型的值,比如

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

則v的Kind方法調(diào)用仍然返回的是reflect.Int,盡管x的靜態(tài)類(lèi)型是MyInt。也可以說(shuō),Kind`不會(huì)像Type`一樣將MyInt和int當(dāng)作兩種類(lèi)型來(lái)對(duì)待。

2.從映射對(duì)象到接口的值

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

通過(guò)利用Interface的方法我們可以將interface.Value恢復(fù)至接口類(lèi)型,實(shí)際上這個(gè)方法將type和value信息包裝至interface類(lèi)型并且返回該值。

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

因此我們可以說(shuō)

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

打印float64類(lèi)型的值,其實(shí)是接口類(lèi)型變量v的映射。

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

fmt.Println(v.Interface())

(為什么不是fmt.Println(v)?因?yàn)橥ㄟ^(guò)v是reflect.Value類(lèi)型.)因?yàn)槲覀兊闹档讓邮莊loat64類(lèi)型,因此我們甚至可以浮點(diǎn)類(lèi)型的格式打印.

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

結(jié)果是

3.4e+00

因此我們不用類(lèi)型斷言v.Interface{}到float64類(lèi)型。因?yàn)榻涌陬?lèi)型內(nèi)部保存著值的信息,Printf函數(shù)能夠恢復(fù)這些信息。

簡(jiǎn)單的說(shuō)Interface是ValueOf的反操作,除非這個(gè)值總是靜態(tài)的Interface類(lèi)型。

改變接口對(duì)象,他的值必須是可改變的

第三法則比較微妙并且容易混淆,但是如果從第一準(zhǔn)則開(kāi)始看的話(huà),那么還是比較容易理解的。

這是一條錯(cuò)誤的語(yǔ)句,但是這個(gè)錯(cuò)誤值得我們研究

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

如果你運(yùn)行這條語(yǔ)句則會(huì)有下面的報(bào)錯(cuò)信息

panic: reflect.Value.SetFloat using unaddressable value

因?yàn)樽兞縱是不可更改的,所以提示值7.1是不可尋址的。可賦值是value的一個(gè)特性,但是并不是所以的value都具有這個(gè)特性。

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

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

結(jié)果是

settability of v: false

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

可賦值的有點(diǎn)像是可尋址的,但是會(huì)更嚴(yán)格。映射對(duì)象可以更改存儲(chǔ)值的特性可以用來(lái)創(chuàng)建新的映射對(duì)象。映射對(duì)象包含原始的數(shù)據(jù)項(xiàng)是決定映射對(duì)象可賦值的關(guān)鍵。當(dāng)下面代碼運(yùn)行時(shí)

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

只是將x的拷貝到reflect.ValueOf,因此reflect.ValueOf的返回值是x的復(fù)制項(xiàng),而不是x本身。假如下面這條語(yǔ)句可以正常運(yùn)行

v.SetFloat(5.4)

盡管v看起來(lái)是由x創(chuàng)建的,但是并不會(huì)更新x的值,因?yàn)檫@條語(yǔ)句會(huì)更新x拷貝值的值,但是并不影響x本身,因此可更改的這一特性就是為了避免這種操作。

雖然這看起來(lái)很古怪,但其實(shí)這是一種很熟悉的操作。比如我們將x值賦值給一個(gè)方法

f(x)

我們本身不想修改x的值,因?yàn)閭魅氲闹皇莤值的拷貝,但是如果我們想修改x的值,那么我們需要傳送x的地址(也就是x的指針)

f(&x)

這種操作是簡(jiǎn)單明了的,其實(shí)對(duì)于映射也是一樣的。如果我們想通過(guò)映射修改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())

結(jié)果

type of p: *float64
settability of p: false

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

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

結(jié)果為

settability of v: true

現(xiàn)在v是一個(gè)可修改的映射對(duì)象。并且v代表x,因此我們可以使用v.SetFloat()來(lái)修改x的值。

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

輸出結(jié)果為

7.1
7.1

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

Struct

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

這有一個(gè)修改結(jié)構(gòu)體變量t的例子。因?yàn)槲覀円薷慕Y(jié)構(gòu)體的字段,所以我們使用結(jié)構(gòu)體指針創(chuàng)建結(jié)構(gòu)體對(duì)象。我們使用typeOfT代表t的數(shù)據(jù)類(lèi)型,并通過(guò)NumField方法迭代結(jié)構(gòu)體的字段。主意:我們只是提取出結(jié)構(gòu)體類(lèi)型字段的的名字,而他們的reflect.Value對(duì)象。

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())
}

輸出結(jié)果是

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

值得注意的是只有可導(dǎo)出的字段才能使可修改的。

因?yàn)閟包含一個(gè)可修改的映射對(duì)象,所以我們可以修改結(jié)構(gòu)體的字段

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

結(jié)果為

t is now {77 Sunset Strip}

審核編輯:黃飛

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 接口
    +關(guān)注

    關(guān)注

    33

    文章

    8933

    瀏覽量

    153189
  • 變量
    +關(guān)注

    關(guān)注

    0

    文章

    614

    瀏覽量

    28819

原文標(biāo)題:GOLANG接口三個(gè)特性

文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    如何判斷晶體管的類(lèi)型及三個(gè)電極

    晶體管是電子元器件中常用的一種,用來(lái)放大電信號(hào)、控制電流等。晶體管通常由三個(gè)電極組成:基極、發(fā)射極和集電極。不同類(lèi)型的晶體管電極排列方式和特性不同,因此需要通過(guò)判斷電極類(lèi)型和排列方式來(lái)確定晶體管的類(lèi)型。下面介紹一下如何判斷晶體管
    的頭像 發(fā)表于 06-03 09:44 ?1.1w次閱讀

    Golang接口的作用和應(yīng)用場(chǎng)景

    Golang(Go)作為一門(mén)現(xiàn)代的靜態(tài)類(lèi)型編程語(yǔ)言,提供了許多強(qiáng)大的特性,其中之一便是接口(interface)。接口Golang中的一
    的頭像 發(fā)表于 12-05 10:44 ?1359次閱讀

    異步主軸電機(jī)的驅(qū)動(dòng)控制三個(gè)基本的特性

    0引言作為數(shù)控機(jī)床的重要組成部分,異步主軸電機(jī)的驅(qū)動(dòng)控制需具備動(dòng)態(tài)響應(yīng)快、控制精度高與調(diào)速范圍廣三個(gè)基本的特性[1]。“間接磁場(chǎng)定向控制[2]”與“弱磁控制”組合是異步主軸電機(jī)常用的驅(qū)動(dòng)控制方式
    發(fā)表于 09-06 06:22

    極管基本特性介紹

    講解常用的NPN極管,穿插介紹一些必須使用PNP極管的電路知識(shí)。如圖1所示,極管的三個(gè)引腳分別是基極(Base)、發(fā)射極(Emitte
    發(fā)表于 12-30 07:30

    功放三個(gè)技術(shù)指標(biāo)如何測(cè)量?

    功放三個(gè)技術(shù)指標(biāo)如何測(cè)量? 功放的主要技術(shù)指標(biāo)有三個(gè):頻率特性、額定輸出功率、失真度。本文從量化的角度出發(fā),提供上述三個(gè)技術(shù)指標(biāo)的測(cè)
    發(fā)表于 03-31 10:04 ?1.5w次閱讀

    技嘉 RTX 3060 Ti:三個(gè)HDMI、三個(gè)DisplayPort、 8+6針輔助供電接口

    是配備了六個(gè)輸出接口,包括三個(gè)HDMI、三個(gè)DisplayPort,相比之下公版和幾乎所有非公版都是一個(gè)HDMI、
    的頭像 發(fā)表于 11-24 09:38 ?1w次閱讀

    golang反射和接口是如何工作 使用反射有什么注意點(diǎn)?

    【導(dǎo)讀】golang反射和接口是如何工作?使用反射有什么注意點(diǎn)?本文對(duì)go反射做了詳細(xì)介紹。 反射用法 反射定律 從接口值到反射對(duì)象的反射 反射是一種檢查存儲(chǔ)在
    的頭像 發(fā)表于 06-02 11:44 ?2650次閱讀

    golang反射和接口是如何工作?

    【導(dǎo)讀】golang反射和接口是如何工作?使用反射有什么注意點(diǎn)?本文對(duì)go反射做了詳細(xì)介紹。 反射用法 反射定律 從接口值到反射對(duì)象的反射 反射是一種檢查存儲(chǔ)在
    的頭像 發(fā)表于 06-13 11:45 ?1717次閱讀

    使用golang channel的諸多特性和技巧

    ? 本文介紹了使用 golang channel 的諸多特性和技巧,已經(jīng)熟悉了 go 語(yǔ)言特性的小伙伴也可以看看,很有啟發(fā)。
    的頭像 發(fā)表于 09-06 15:14 ?2048次閱讀
    使用<b class='flag-5'>golang</b> channel的諸多<b class='flag-5'>特性</b>和技巧

    詳解golang事務(wù)的種寫(xiě)法

    本文中作者展示了 golang 事務(wù)的種寫(xiě)法。
    的頭像 發(fā)表于 03-16 08:52 ?5601次閱讀

    什么是虛擬仿真 虛擬仿真的三個(gè)特性介紹

    虛擬仿真技術(shù)主要具備以下三個(gè)特性:沉浸性(Immersion)、交互性(Interaction)、構(gòu)想性(Imagination),又稱(chēng)“3I”特性
    的頭像 發(fā)表于 12-13 15:48 ?8744次閱讀

    Golang實(shí)現(xiàn)一個(gè)簡(jiǎn)單的http代理

    本文詳細(xì)介紹Golang 實(shí)現(xiàn) http 代理的實(shí)現(xiàn),在實(shí)際業(yè)務(wù)中有需求的同學(xué)可以學(xué)起來(lái)了!
    的頭像 發(fā)表于 04-10 11:29 ?1645次閱讀

    個(gè)快速應(yīng)用程序開(kāi)發(fā)(RAD)工具(Golang版)

    SNMPAgent Builder(Golang版)是一個(gè)快速應(yīng)用程序開(kāi)發(fā)(RAD)工具,用于基于Golang 的 SNMP代理開(kāi)發(fā)。提供了一個(gè)直觀的圖形用戶(hù)界面,用于自動(dòng)執(zhí)行各種SN
    的頭像 發(fā)表于 04-13 09:30 ?1756次閱讀

    Pandas函數(shù)的三個(gè)接口介紹

    本文主要介紹pandas.DataFrame的三個(gè)接口,即assign、eval、query,分別用于賦值、查詢(xún)和執(zhí)行計(jì)算。 01 assign 在數(shù)據(jù)分析處理中,賦值產(chǎn)生新的列是非常高頻的應(yīng)用場(chǎng)
    的頭像 發(fā)表于 11-01 16:38 ?686次閱讀
    Pandas函數(shù)的<b class='flag-5'>三個(gè)</b><b class='flag-5'>接口</b><b class='flag-5'>介紹</b>

    串聯(lián)諧振電路的三個(gè)特征

    串聯(lián)諧振電路的三個(gè)特征? 串聯(lián)諧振電路是一種重要的電路結(jié)構(gòu),具有許多特征和應(yīng)用。本文將詳細(xì)介紹串聯(lián)諧振電路的三個(gè)主要特征,并對(duì)其原理和應(yīng)用進(jìn)行詳細(xì)討論。 首先,串聯(lián)諧振電路具有共振頻率。共振頻率是指
    的頭像 發(fā)表于 12-20 14:54 ?2074次閱讀