RM新时代网站-首页

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

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

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

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

Linux愛(ài)好者 ? 來(lái)源:github ? 作者:LeoYang90 ? 2021-06-13 11:45 ? 次閱讀

【導(dǎo)讀】golang反射和接口是如何工作?使用反射有什么注意點(diǎn)?本文對(duì)go反射做了詳細(xì)介紹。

反射用法

反射定律

從接口值到反射對(duì)象的反射

反射是一種檢查存儲(chǔ)在接口變量中的(類(lèi)型,值)對(duì)的機(jī)制。作為一個(gè)開(kāi)始,我們需要知道reflect包中的兩個(gè)類(lèi)型:Type和Value。這兩種類(lèi)型給了我們?cè)L問(wèn)一個(gè)接口變量中所包含的內(nèi)容的途徑,另外兩個(gè)簡(jiǎn)單的函數(shù)reflect.Typeof和reflect.Valueof可以檢索一個(gè)接口值的reflect.Type和reflect.Value部分。

package main

import (

“fmt”

“reflect”

func main() {

var x float64 = 3.4

fmt.Println(“type:”, reflect.TypeOf(x))

}

reflect.Typeof 簽名里就包含了一個(gè)空接口:

func TypeOf(i interface{}) Type

當(dāng)我們調(diào)用reflect.Typeof(x)的時(shí)候,x首先被保存到一個(gè)空接口中,這個(gè)空接口然后被作為參數(shù)傳遞。reflect.Typeof 會(huì)把這個(gè)空接口拆包(unpack)恢復(fù)出類(lèi)型信息。

當(dāng)然,reflect.Valueof可以把值恢復(fù)出來(lái)

var x float64 = 3.4

fmt.Println(“value:”, reflect.ValueOf(x))//Valueof方法會(huì)返回一個(gè)Value類(lèi)型的對(duì)象

reflect.Type和reflect.Value這兩種類(lèi)型都提供了大量的方法讓我們可以檢查和操作這兩種類(lèi)型。一個(gè)重要的例子是:

Value類(lèi)型有一個(gè) Type 方法可以返回reflect.Value類(lèi)型的Type(這個(gè)方法返回的是值的靜態(tài)類(lèi)型即static type,也就是說(shuō)如果定義了type MyInt int64,那么這個(gè)函數(shù)返回的是MyInt類(lèi)型而不是int64

Type 和 Value 都有一個(gè)Kind方法可以返回一個(gè)常量用于指示一個(gè)項(xiàng)到底是以什么形式(也就是底層類(lèi)型即underlying type,繼續(xù)前面括號(hào)里提到的,Kind返回的是int64而不是MyInt)存儲(chǔ)的,這些常量包括:Unit, Float64, Slice等等。而且,有關(guān)Value類(lèi)型的帶有名字諸如Int和Float的方法可讓讓我們獲取存在里面的值(比如int64和float64):

var x float64 = 3.4

v := reflect.ValueOf(x)

fmt.Println(“type:”, v.Type())

fmt.Println(“kind is float64:”, v.Kind() == reflect.Float64)

fmt.Println(“value:”, v.Float())

type: float64

kind is float64: true

value: 3.4

反射庫(kù)里有倆性質(zhì)值得單獨(dú)拿出來(lái)說(shuō)說(shuō)。第一個(gè)性質(zhì)是,為了保持API簡(jiǎn)單,Value的”setter”和“getter”類(lèi)型的方法操作的是可以包含某個(gè)值的最大類(lèi)型:比如,所有的有符號(hào)整型,只有針對(duì)int64類(lèi)型的方法,因?yàn)樗撬械挠蟹?hào)整型中最大的一個(gè)類(lèi)型。也就是說(shuō),Value的Int方法返回的是一個(gè)int64,同時(shí)SetInt的參數(shù)類(lèi)型采用的是一個(gè)int64;所以,必要時(shí)要轉(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è)地方必須進(jìn)行強(qiáng)制類(lèi)型轉(zhuǎn)換!

第二個(gè)性質(zhì)是,反射對(duì)象(reflection object)的Kind描述的是底層類(lèi)型(underlying type)

從反射隊(duì)形到接口值的反射

就像物理學(xué)上的反射,Go中到反射可以生成它的逆。

給定一個(gè)reflect.Value,我們能用Interface方法把它恢復(fù)成一個(gè)接口值;效果上就是這個(gè)Interface方法把類(lèi)型和值的信息打包成一個(gè)接口表示并且返回結(jié)果:

func (v Value) Interface() interface{}

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

fmt.Println(y)

我們甚至可以做得更好一些,fmt.Println等方法的參數(shù)是一個(gè)空接口類(lèi)型的值,所以我們可以讓fmt包自己在內(nèi)部完成我們?cè)谏厦娲a中做的工作。因此,為了正確打印一個(gè)reflect.Value,我們只需把Interface方法的返回值直接傳遞給這個(gè)格式化輸出例程:

fmt.Println(v.Interface())

fmt.Printf(“value is %7.1e

”, v.Interface())

3.4e+00

還有就是,我們不需要對(duì)v.Interface方法的結(jié)果調(diào)用類(lèi)型斷言(type-assert)為float64;空接口類(lèi)型值內(nèi)部包含有具體值的類(lèi)型信息,并且Printf方法會(huì)把它恢復(fù)出來(lái)。

簡(jiǎn)要的說(shuō),Interface方法是Valueof函數(shù)的逆,除了它的返回值的類(lèi)型總是interface{}靜態(tài)類(lèi)型。

為了修改一個(gè)反射對(duì)象,值必須是settable的

下面是一些不能正常運(yùn)行的代碼,但是很值得研究:

var x float64 = 3.4

v := reflect.ValueOf(x)

v.SetFloat(7.1) // Error: will panic.

問(wèn)題不是出在值7.1不是可以尋址的,而是出在v不是settable的。Settability是Value的一條性質(zhì),而且,不是所有的Value都具備這條性質(zhì)。

Value的CanSet方法用與測(cè)試一個(gè)Value的settablity;在我們的例子中,

var x float64 = 3.4

v := reflect.ValueOf(x)

fmt.Println(“settability of v:”, v.CanSet())

settability of v: false

如果對(duì)一個(gè)non-settable的Value調(diào)用Set方法會(huì)出現(xiàn)錯(cuò)誤。但是,settability到底是什么呢?

settability有點(diǎn)像addressability,但是更加嚴(yán)格。

settability是一個(gè)性質(zhì),描述的是一個(gè)反射對(duì)象能夠修改創(chuàng)造它的那個(gè)實(shí)際存儲(chǔ)的值的能力。settability由反射對(duì)象是否保存原始項(xiàng)(original item)而決定。

var x float64 = 3.4

v := reflect.ValueOf(x)

我們傳遞了x的一個(gè)副本給reflect.Valueof函數(shù),所以作為reflect.Valueof參數(shù)被創(chuàng)造出來(lái)的接口值只是x的一個(gè)副本,而不是x本身。

因?yàn)?,如果下面這條語(yǔ)句

v.SetFloat(7.1)

執(zhí)行成功(當(dāng)然不可能執(zhí)行成功啦,假設(shè)而已),它不會(huì)更新x,即使v看起來(lái)像是從x創(chuàng)造而來(lái),所以它更新的只是存儲(chǔ)在反射值內(nèi)部的x的一個(gè)副本,而x本身不受絲毫影響,所以如果真這樣的話,將會(huì)非常那令人困惑,而且一點(diǎn)用都沒(méi)有!所以,這么干是非法的,而settability就是用來(lái)阻止這種哦給你非法狀況出現(xiàn)的。

如果我們想通過(guò)反射來(lái)修改x,我們必須把我們想要修改的值的指針傳給一個(gè)反射庫(kù)。

首先,我們像平常一樣初始化x,然后創(chuàng)造一個(gè)指向它的反射值,叫做p.

var x float64 = 3.4

p := reflect.ValueOf(&x) // Note: take the address of x.注意這里哦!我們把x地址傳進(jìn)去了!

fmt.Println(“type of p:”, p.Type())

fmt.Println(“settability of p:”, p.CanSet())

type of p: *float64

settability of p: false

反射對(duì)象p不是settable的,但是我們想要設(shè)置的不是p,而是(效果上來(lái)說(shuō))*p。為了得到p指向的東西,我們調(diào)用Value的Elem方法,這樣就能迂回繞過(guò)指針,同時(shí)把結(jié)果保存在叫v的Value中:

v := p.Elem()

fmt.Println(“settability of v:”, v.CanSet())

settability of v: true

現(xiàn)在v就是一個(gè)settable的反射對(duì)象了,并且因?yàn)関表示x,我們最終能夠通過(guò)v.SetFloat方法來(lái)修改x的值:

v.SetFloat(7.1)

fmt.Println(v.Interface())

fmt.Println(x)

輸出正是我們所期待的,反射理解起來(lái)有點(diǎn)困難,但是它確實(shí)正在做編程語(yǔ)言要做的,盡管是通過(guò)掩蓋了所發(fā)生的一切的反射Types和Vlues來(lái)實(shí)現(xiàn)的。這樣好了,你就直接記住反射Values為了修改它們所表示的東西必須要有這些東西的地址。

type 的方法集

來(lái)源 :Golang學(xué)習(xí) - reflect 包https://www.cnblogs.com/golove/p/5909541.html

type Type interface {

// Methods applicable to all types.

// 獲取 t 類(lèi)型的值在分配內(nèi)存時(shí)的字節(jié)對(duì)齊值。

Align() int

// 獲取 t 類(lèi)型的值作為結(jié)構(gòu)體字段時(shí)的字節(jié)對(duì)齊值。

FieldAlign() int

// 根據(jù)索引獲取 t 類(lèi)型的方法,如果方法不存在,則 panic。

// 如果 t 是一個(gè)實(shí)際的類(lèi)型,則返回值的 Type 和 Func 字段會(huì)列出接收者。

// 如果 t 只是一個(gè)接口,則返回值的 Type 不列出接收者,F(xiàn)unc 為空值。

Method(int) Method

// 根據(jù)名稱(chēng)獲取 t 類(lèi)型的方法。

MethodByName(string) (Method, bool)

// 獲取 t 類(lèi)型的方法數(shù)量。

NumMethod() int

// 獲取 t 類(lèi)型在其包中定義的名稱(chēng),未命名類(lèi)型則返回空字符串。

Name() string

// 獲取 t 類(lèi)型所在包的名稱(chēng),未命名類(lèi)型則返回空字符串。

PkgPath() string

// 獲取 t 類(lèi)型的值在分配內(nèi)存時(shí)的大小,功能和 unsafe.SizeOf 一樣。

Size() uintptr

// 獲取 t 類(lèi)型的字符串描述,不要通過(guò) String 來(lái)判斷兩種類(lèi)型是否一致。

String() string

// 獲取 t 類(lèi)型的類(lèi)別。

Kind() Kind

// 判斷 t 類(lèi)型是否實(shí)現(xiàn)了 u 接口。

Implements(u Type) bool

// 判斷 t 類(lèi)型的值可否賦值給 u 類(lèi)型。

AssignableTo(u Type) bool

// 判斷 t 類(lèi)型的值可否轉(zhuǎn)換為 u 類(lèi)型。

ConvertibleTo(u Type) bool

// 判斷 t 類(lèi)型的值可否進(jìn)行比較操作

Comparable() bool

// Methods applicable only to some types, depending on Kind.

// 特定類(lèi)型的函數(shù):

//

// Int*, Uint*, Float*, Complex*: Bits

// Array: Elem, Len

// Chan: ChanDir, Elem

// Func: In, NumIn, Out, NumOut, IsVariadic.

// Map: Key, Elem

// Ptr: Elem

// Slice: Elem

// Struct: Field, FieldByIndex, FieldByName, FieldByNameFunc, NumField

// 獲取數(shù)值類(lèi)型的位寬,t 必須是整型、浮點(diǎn)型、復(fù)數(shù)型

Bits() int

// 獲取通道的方向

ChanDir() ChanDir

// For concreteness, if t represents func(x int, y 。.. float64), then

//

// t.NumIn() == 2

// t.In(0) is the reflect.Type for “int”

// t.In(1) is the reflect.Type for “[]float64”

// t.IsVariadic() == true

// 判斷函數(shù)是否具有可變參數(shù)。

// 如果有可變參數(shù),則 t.In(t.NumIn()-1) 將返回一個(gè)切片。

IsVariadic() bool

// 數(shù)組、切片、映射、通道、指針、接口

// 獲取元素類(lèi)型、獲取指針?biāo)笇?duì)象類(lèi)型,獲取接口的動(dòng)態(tài)類(lèi)型

Elem() Type

// 根據(jù)索引獲取字段

Field(i int) StructField

// 根據(jù)索引鏈獲取嵌套字段

FieldByIndex(index []int) StructField

// 根據(jù)名稱(chēng)獲取字段

FieldByName(name string) (StructField, bool)

// 根據(jù)指定的匹配函數(shù) math 獲取字段

FieldByNameFunc(match func(string) bool) (StructField, bool)

// 根據(jù)索引獲取函數(shù)的參數(shù)信息

In(i int) Type

// Key returns a map type‘s key type.

// It panics if the type’s Kind is not Map.

Key() Type

// Len returns an array type‘s length.

// It panics if the type’s Kind is not Array.

Len() int

// 獲取字段數(shù)量

NumField() int

// 獲取函數(shù)的參數(shù)數(shù)量

NumIn() int

// 獲取函數(shù)的返回值數(shù)量

NumOut() int

// 根據(jù)索引獲取函數(shù)的返回值信息

Out(i int) Type

common() *rtype

uncommon() *uncommonType

}

value 方法集

// 特殊

// 判斷 v 值是否可尋址

// 1、指針的 Elem() 可尋址

// 2、切片的元素可尋址

// 3、可尋址數(shù)組的元素可尋址

// 4、可尋址結(jié)構(gòu)體的字段可尋址,方法不可尋址

// 也就是說(shuō),如果 v 值是指向數(shù)組的指針“&數(shù)組”,通過(guò) v.Elem() 獲取該指針指向的數(shù)組,那么

// 該數(shù)組就是可尋址的,同時(shí)該數(shù)組的元素也是可尋址的,如果 v 就是一個(gè)普通數(shù)組,不是通過(guò)解引

// 用得到的數(shù)組,那么該數(shù)組就不可尋址,其元素也不可尋址。結(jié)構(gòu)體亦然。

func (v Value) CanAddr() bool

// 獲取 v 值的地址,相當(dāng)于 & 取地址操作。v 值必須可尋址。

func (v Value) Addr() reflect.Value

// 判斷 v 值是否可以被修改。只有可尋址的 v 值可被修改。

// 結(jié)構(gòu)體中的非導(dǎo)出字段(通過(guò) Field() 等方法獲取的)不能修改,所有方法不能修改。

func (v Value) CanSet() bool

// 判斷 v 值是否可以轉(zhuǎn)換為接口類(lèi)型

// 結(jié)構(gòu)體中的非導(dǎo)出字段(通過(guò) Field() 等方法獲取的)不能轉(zhuǎn)換為接口類(lèi)型

func (v Value) CanInterface() bool

// 將 v 值轉(zhuǎn)換為空接口類(lèi)型。v 值必須可轉(zhuǎn)換為接口類(lèi)型。

func (v Value) Interface() interface{}

// 使用一對(duì) uintptr 返回接口的數(shù)據(jù)

func (v Value) InterfaceData() [2]uintptr

// 指針

// 將 v 值轉(zhuǎn)換為 uintptr 類(lèi)型,v 值必須是切片、映射、通道、函數(shù)、指針、自由指針。

func (v Value) Pointer() uintptr

// 獲取 v 值的地址。v 值必須是可尋址類(lèi)型(CanAddr)。

func (v Value) UnsafeAddr() uintptr

// 將 UnsafePointer 類(lèi)別的 v 值修改為 x,v 值必須是 UnsafePointer 類(lèi)別,必須可修改。

func (v Value) SetPointer(x unsafe.Pointer)

// 判斷 v 值是否為 nil,v 值必須是切片、映射、通道、函數(shù)、接口、指針。

// IsNil 并不總等價(jià)于 Go 的潛在比較規(guī)則,比如對(duì)于 var i interface{},i == nil 將返回

// true,但是 reflect.ValueOf(i).IsNil() 將 panic。

func (v Value) IsNil() bool

// 獲取“指針?biāo)傅膶?duì)象”或“接口所包含的對(duì)象”

func (v Value) Elem() reflect.Value

// 通用

// 獲取 v 值的字符串描述

func (v Value) String() string

// 獲取 v 值的類(lèi)型

func (v Value) Type() reflect.Type

// 返回 v 值的類(lèi)別,如果 v 是空值,則返回 reflect.Invalid。

func (v Value) Kind() reflect.Kind

// 獲取 v 的方法數(shù)量

func (v Value) NumMethod() int

// 根據(jù)索引獲取 v 值的方法,方法必須存在,否則 panic

// 使用 Call 調(diào)用方法的時(shí)候不用傳入接收者,Go 會(huì)自動(dòng)把 v 作為接收者傳入。

func (v Value) Method(int) reflect.Value

// 根據(jù)名稱(chēng)獲取 v 值的方法,如果該方法不存在,則返回空值(reflect.Invalid)。

func (v Value) MethodByName(string) reflect.Value

// 判斷 v 本身(不是 v 值)是否為零值。

// 如果 v 本身是零值,則除了 String 之外的其它所有方法都會(huì) panic。

func (v Value) IsValid() bool

// 將 v 值轉(zhuǎn)換為 t 類(lèi)型,v 值必須可轉(zhuǎn)換為 t 類(lèi)型,否則 panic。

func (v Value) Convert(t Type) reflect.Value

// 獲取

// 獲取 v 值的內(nèi)容,如果 v 值不是有符號(hào)整型,則 panic。

func (v Value) Int() int64

// 獲取 v 值的內(nèi)容,如果 v 值不是無(wú)符號(hào)整型(包括 uintptr),則 panic。

func (v Value) Uint() uint64

// 獲取 v 值的內(nèi)容,如果 v 值不是浮點(diǎn)型,則 panic。

func (v Value) Float() float64

// 獲取 v 值的內(nèi)容,如果 v 值不是復(fù)數(shù)型,則 panic。

func (v Value) Complex() complex128

// 獲取 v 值的內(nèi)容,如果 v 值不是布爾型,則 panic。

func (v Value) Bool() bool

// 獲取 v 值的長(zhǎng)度,v 值必須是字符串、數(shù)組、切片、映射、通道。

func (v Value) Len() int

// 獲取 v 值的容量,v 值必須是數(shù)值、切片、通道。

func (v Value) Cap() int

// 獲取 v 值的第 i 個(gè)元素,v 值必須是字符串、數(shù)組、切片,i 不能超出范圍。

func (v Value) Index(i int) reflect.Value

// 獲取 v 值的內(nèi)容,如果 v 值不是字節(jié)切片,則 panic。

func (v Value) Bytes() []byte

// 獲取 v 值的切片,切片長(zhǎng)度 = j - i,切片容量 = v.Cap() - i。

// v 必須是字符串、數(shù)值、切片,如果是數(shù)組則必須可尋址。i 不能超出范圍。

func (v Value) Slice(i, j int) reflect.Value

// 獲取 v 值的切片,切片長(zhǎng)度 = j - i,切片容量 = k - i。

// i、j、k 不能超出 v 的容量。i 《= j 《= k。

// v 必須是字符串、數(shù)值、切片,如果是數(shù)組則必須可尋址。i 不能超出范圍。

func (v Value) Slice3(i, j, k int) reflect.Value

// 根據(jù) key 鍵獲取 v 值的內(nèi)容,v 值必須是映射。

// 如果指定的元素不存在,或 v 值是未初始化的映射,則返回零值(reflect.ValueOf(nil))

func (v Value) MapIndex(key Value) reflect.Value

// 獲取 v 值的所有鍵的無(wú)序列表,v 值必須是映射。

// 如果 v 值是未初始化的映射,則返回空列表。

func (v Value) MapKeys() []reflect.Value

// 判斷 x 是否超出 v 值的取值范圍,v 值必須是有符號(hào)整型。

func (v Value) OverflowInt(x int64) bool

// 判斷 x 是否超出 v 值的取值范圍,v 值必須是無(wú)符號(hào)整型。

func (v Value) OverflowUint(x uint64) bool

// 判斷 x 是否超出 v 值的取值范圍,v 值必須是浮點(diǎn)型。

func (v Value) OverflowFloat(x float64) bool

// 判斷 x 是否超出 v 值的取值范圍,v 值必須是復(fù)數(shù)型。

func (v Value) OverflowComplex(x complex128) bool

------------------------------

// 設(shè)置(這些方法要求 v 值必須可修改)

// 設(shè)置 v 值的內(nèi)容,v 值必須是有符號(hào)整型。

func (v Value) SetInt(x int64)

// 設(shè)置 v 值的內(nèi)容,v 值必須是無(wú)符號(hào)整型。

func (v Value) SetUint(x uint64)

// 設(shè)置 v 值的內(nèi)容,v 值必須是浮點(diǎn)型。

func (v Value) SetFloat(x float64)

// 設(shè)置 v 值的內(nèi)容,v 值必須是復(fù)數(shù)型。

func (v Value) SetComplex(x complex128)

// 設(shè)置 v 值的內(nèi)容,v 值必須是布爾型。

func (v Value) SetBool(x bool)

// 設(shè)置 v 值的內(nèi)容,v 值必須是字符串。

func (v Value) SetString(x string)

// 設(shè)置 v 值的長(zhǎng)度,v 值必須是切片,n 不能超出范圍,不能為負(fù)數(shù)。

func (v Value) SetLen(n int)

// 設(shè)置 v 值的內(nèi)容,v 值必須是切片,n 不能超出范圍,不能小于 Len。

func (v Value) SetCap(n int)

// 設(shè)置 v 值的內(nèi)容,v 值必須是字節(jié)切片。x 可以超出 v 值容量。

func (v Value) SetBytes(x []byte)

// 設(shè)置 v 值的鍵和值,如果鍵存在,則修改其值,如果鍵不存在,則添加鍵和值。

// 如果將 val 設(shè)置為零值(reflect.ValueOf(nil)),則刪除該鍵。

// 如果 v 值是一個(gè)未初始化的 map,則 panic。

func (v Value) SetMapIndex(key, val reflect.Value)

// 設(shè)置 v 值的內(nèi)容,v 值必須可修改,x 必須可以賦值給 v 值。

func (v Value) Set(x reflect.Value)

------------------------------

// 結(jié)構(gòu)體

// 獲取 v 值的字段數(shù)量,v 值必須是結(jié)構(gòu)體。

func (v Value) NumField() int

// 根據(jù)索引獲取 v 值的字段,v 值必須是結(jié)構(gòu)體。如果字段不存在則 panic。

func (v Value) Field(i int) reflect.Value

// 根據(jù)索引鏈獲取 v 值的嵌套字段,v 值必須是結(jié)構(gòu)體。

func (v Value) FieldByIndex(index []int) reflect.Value

// 根據(jù)名稱(chēng)獲取 v 值的字段,v 值必須是結(jié)構(gòu)體。

// 如果指定的字段不存在,則返回零值(reflect.ValueOf(nil))

func (v Value) FieldByName(string) reflect.Value

// 根據(jù)匹配函數(shù) match 獲取 v 值的字段,v 值必須是結(jié)構(gòu)體。

// 如果沒(méi)有匹配的字段,則返回零值(reflect.ValueOf(nil))

func (v Value) FieldByNameFunc(match func(string) bool) Value

// 函數(shù)

// 通過(guò)參數(shù)列表 in 調(diào)用 v 值所代表的函數(shù)(或方法)。函數(shù)的返回值存入 r 中返回。

// 要傳入多少參數(shù)就在 in 中存入多少元素。

// Call 即可以調(diào)用定參函數(shù)(參數(shù)數(shù)量固定),也可以調(diào)用變參函數(shù)(參數(shù)數(shù)量可變)。

func (v Value) Call(in []Value) (r []Value)

// 通過(guò)參數(shù)列表 in 調(diào)用 v 值所代表的函數(shù)(或方法)。函數(shù)的返回值存入 r 中返回。

// 函數(shù)指定了多少參數(shù)就在 in 中存入多少元素,變參作為一個(gè)單獨(dú)的參數(shù)提供。

// CallSlice 只能調(diào)用變參函數(shù)。

func (v Value) CallSlice(in []Value) []Value

// 通道

// 發(fā)送數(shù)據(jù)(會(huì)阻塞),v 值必須是可寫(xiě)通道。

func (v Value) Send(x reflect.Value)

// 接收數(shù)據(jù)(會(huì)阻塞),v 值必須是可讀通道。

func (v Value) Recv() (x reflect.Value, ok bool)

// 嘗試發(fā)送數(shù)據(jù)(不會(huì)阻塞),v 值必須是可寫(xiě)通道。

func (v Value) TrySend(x reflect.Value) bool

// 嘗試接收數(shù)據(jù)(不會(huì)阻塞),v 值必須是可讀通道。

func (v Value) TryRecv() (x reflect.Value, ok bool)

// 關(guān)閉通道,v 值必須是通道。

func (v Value) Close()

// 示例

var f1 = func(a int, b []int) { fmt.Println(a, b) }

var f2 = func(a int, b 。..int) { fmt.Println(a, b) }

func main() {

v1 := reflect.ValueOf(f1)

v2 := reflect.ValueOf(f2)

a := reflect.ValueOf(1)

b := reflect.ValueOf([]int{1, 2, 3})

v1.Call([]reflect.Value{a, b})

v2.Call([]reflect.Value{a, a, a, a, a, a})

//v1.CallSlice([]reflect.Value{a, b}) // 非變參函數(shù),不能用 CallSlice。

v2.CallSlice([]reflect.Value{a, b})

}

樣例

類(lèi)型的字段標(biāo)識(shí)

下面是分析一個(gè)struct值,t,的簡(jiǎn)單例子。我們用這個(gè)struct的地址創(chuàng)建一個(gè)反射對(duì)象,因?yàn)槲覀兿胍粫?huì)改變它的值。然后我們把typeofT變量設(shè)置為這個(gè)反射對(duì)象的類(lèi)型,接著使用一些直接的方法調(diào)用(細(xì)節(jié)請(qǐng)見(jiàn)reflect包)來(lái)迭代各個(gè)域。注意,我們從struct類(lèi)型中提取了各個(gè)域的名字,但是這些域本身都是reflect.Value對(duì)象。

type T struct {

A int

B string

}

t := T{23, “skidoo”}

s := reflect.ValueOf(&t).Elem()

typeOfT := s.Type()//把s.Type()返回的Type對(duì)象復(fù)制給typeofT,typeofT也是一個(gè)反射。

for i := 0; i 《 s.NumField(); i++ {

f := s.Field(i)//迭代s的各個(gè)域,注意每個(gè)域仍然是反射。

fmt.Printf(“%d: %s %s = %v

”, i,

typeOfT.Field(i).Name, f.Type(), f.Interface())//提取了每個(gè)域的名字

}

0: A int = 23

1: B string = skidoo

reflect.Type的Field方法將返回一個(gè)reflect.StructField,里面含有每個(gè)成員的名字、類(lèi)型和可選的成員標(biāo)簽等信息。

因?yàn)閟包含了一個(gè)settable的反射對(duì)象,所以我們可以修改這個(gè)structure的各個(gè)域。

s.Field(0).SetInt(77)

s.Field(1).SetString(“Sunset Strip”)

fmt.Println(“t is now”, t)

t is now {77 Sunset Strip}

類(lèi)型的方法集

func Print(x interface{}) {

v := reflect.ValueOf(x)

t := v.Type()

fmt.Printf(“type %s

”, t)

for i := 0; i 《 v.NumMethod(); i++ {

methType := v.Method(i).Type()

fmt.Printf(“func (%s) %s%s

”, t, t.Method(i).Name,

strings.TrimPrefix(methType.String(), “func”))

}

}

reflect.Type和reflect.Value都提供了一個(gè)Method方法。每次t.Method(i)調(diào)用將一個(gè)reflect.Method的實(shí)例,對(duì)應(yīng)一個(gè)用于描述一個(gè)方法的名稱(chēng)和類(lèi)型的結(jié)構(gòu)體。每次v.Method(i)方法調(diào)用都返回一個(gè)reflect.Value以表示對(duì)應(yīng)的值(§6.4),也就是一個(gè)方法是幫到它的接收者的。使用reflect.Value.Call方法(我們之類(lèi)沒(méi)有演示),將可以調(diào)用一個(gè)Func類(lèi)型的Value,但是這個(gè)例子中只用到了它的類(lèi)型。

methods.Print(time.Hour)

// Output:

// type time.Duration

// func (time.Duration) Hours() float64

// func (time.Duration) Minutes() float64

// func (time.Duration) Nanoseconds() int64

// func (time.Duration) Seconds() float64

// func (time.Duration) String() string

methods.Print(new(strings.Replacer))

// Output:

// type *strings.Replacer

// func (*strings.Replacer) Replace(string) string

// func (*strings.Replacer) WriteString(io.Writer, string) (int, error)

反射的原理

Typeof

Typeof 函數(shù)非常簡(jiǎn)單,在調(diào)用 Typeof 函數(shù)的時(shí)候,變量就已經(jīng)被轉(zhuǎn)化為 interface 類(lèi)型,Typeof 只需要將它的 typ 屬性取出來(lái)即可。

func TypeOf(i interface{}) Type {

eface := *(*emptyInterface)(unsafe.Pointer(&i))

return toType(eface.typ)

}

func toType(t *rtype) Type {

if t == nil {

return nil

}

return t

}

type.Name 函數(shù)

解析類(lèi)型的名稱(chēng)是一個(gè)反射很基礎(chǔ)的功能,它和 String 方法的不同在于,它不會(huì)包含類(lèi)型所在包的名字,例如 main.Cat 與 Cat,所以一定不要用 name 來(lái)區(qū)分類(lèi)型。

從實(shí)現(xiàn)來(lái)看,Name 是建立在 String 函數(shù)的基礎(chǔ)上的,它找到了 。 這個(gè)字符然后分割了字符串。

從下面的代碼中可以看到,rtype 的 str(nameoff) 屬性并不是簡(jiǎn)單的距離,而是距離各個(gè)模塊 types 的距離。

func (t *rtype) Name() string {

if t.tflag&tflagNamed == 0 {

return “”

}

s := t.String()

i := len(s) - 1

for i 》= 0 && s[i] != ‘?!?{

i--

}

return s[i+1:]

}

func (t *rtype) String() string {

s := t.nameOff(t.str).name()

if t.tflag&tflagExtraStar != 0 {

return s[1:]

}

return s

}

func (t *rtype) nameOff(off nameOff) name {

return name{(*byte)(resolveNameOff(unsafe.Pointer(t), int32(off)))}

}

// reflect_resolveNameOff resolves a name offset from a base pointer.

//go:linkname reflect_resolveNameOff reflect.resolveNameOff

func reflect_resolveNameOff(ptrInModule unsafe.Pointer, off int32) unsafe.Pointer {

return unsafe.Pointer(resolveNameOff(ptrInModule, nameOff(off)).bytes)

}

func resolveNameOff(ptrInModule unsafe.Pointer, off nameOff) name {

if off == 0 {

return name{}

}

base := uintptr(ptrInModule)

for md := &firstmoduledata; md != nil; md = md.next {

if base 》= md.types && base 《 md.etypes {

res := md.types + uintptr(off)

if res 》 md.etypes {

println(“runtime: nameOff”, hex(off), “out of range”, hex(md.types), “-”, hex(md.etypes))

throw(“runtime: name offset out of range”)

}

return name{(*byte)(unsafe.Pointer(res))}

}

}

// No module found. see if it is a run time name.

reflectOffsLock()

res, found := reflectOffs.m[int32(off)]

reflectOffsUnlock()

if !found {

println(“runtime: nameOff”, hex(off), “base”, hex(base), “not in ranges:”)

for next := &firstmoduledata; next != nil; next = next.next {

println(“ types”, hex(next.types), “etypes”, hex(next.etypes))

}

throw(“runtime: name offset base pointer out of range”)

}

return name{(*byte)(res)}

}

type.Field

func (t *rtype) Field(i int) StructField {

if t.Kind() != Struct {

panic(“reflect: Field of non-struct type”)

}

tt := (*structType)(unsafe.Pointer(t))

return tt.Field(i)

}

func (t *structType) Field(i int) (f StructField) {

if i 《 0 || i 》= len(t.fields) {

panic(“reflect: Field index out of bounds”)

}

p := &t.fields[i]

f.Type = toType(p.typ)

f.Name = p.name.name()

f.Anonymous = p.embedded()

if !p.name.isExported() {

f.PkgPath = t.pkgPath.name()

}

if tag := p.name.tag(); tag != “” {

f.Tag = StructTag(tag)

}

f.Offset = p.offset()

// NOTE(rsc): This is the only allocation in the interface

// presented by a reflect.Type. It would be nice to avoid,

// at least in the common cases, but we need to make sure

// that misbehaving clients of reflect cannot affect other

// uses of reflect. One possibility is CL 5371098, but we

// postponed that ugliness until there is a demonstrated

// need for the performance. This is issue 2320.

f.Index = []int{i}

return

}

type.Method 方法

對(duì)于 golang 里面的類(lèi)型,它們的方法都是存儲(chǔ)在 uncommon 的部分當(dāng)中,而且他們的數(shù)據(jù)結(jié)構(gòu)是:

type method struct {

name nameOff // name of method

mtyp typeOff // method type (without receiver)

ifn textOff // fn used in interface call (one-word receiver)

tfn textOff // fn used for normal method call

}

數(shù)據(jù)結(jié)構(gòu)中,mtyp 是 method 類(lèi)型的地址,ifn 是接口函數(shù)的地址,tfn 是普通函數(shù)的地址。

它會(huì)被 Method 函數(shù)轉(zhuǎn)換為 Method 類(lèi)型:

type Method struct {

// Name is the method name.

// PkgPath is the package path that qualifies a lower case (unexported)

// method name. It is empty for upper case (exported) method names.

// The combination of PkgPath and Name uniquely identifies a method

// in a method set.

// See https://golang.org/ref/spec#Uniqueness_of_identifiers

Name string

PkgPath string

Type Type // method type

Func Value // func with receiver as first argument

Index int // index for Type.Method

}

Method 的 Type 由 mtyp 而來(lái),F(xiàn)unc 由 tfn/ifn 而來(lái),而 Func 是 Value 類(lèi)型,F(xiàn)unc.typ 還是 mtyp,ptr 是 tfn/ifn。

func (t *rtype) Method(i int) (m Method) {

if t.Kind() == Interface {

tt := (*interfaceType)(unsafe.Pointer(t))

return tt.Method(i)

}

methods := t.exportedMethods()

if i 《 0 || i 》= len(methods) {

panic(“reflect: Method index out of range”)

}

p := methods[i]

pname := t.nameOff(p.name)

m.Name = pname.name()

fl := flag(Func)

mtyp := t.typeOff(p.mtyp)

ft := (*funcType)(unsafe.Pointer(mtyp))

in := make([]Type, 0, 1+len(ft.in()))

in = append(in, t)

for _, arg := range ft.in() {

in = append(in, arg)

}

out := make([]Type, 0, len(ft.out()))

for _, ret := range ft.out() {

out = append(out, ret)

}

mt := FuncOf(in, out, ft.IsVariadic())

m.Type = mt

tfn := t.textOff(p.tfn)

fn := unsafe.Pointer(&tfn)

m.Func = Value{mt.(*rtype), fn, fl}

m.Index = i

return m

}

func (t *rtype) exportedMethods() []method {

ut := t.uncommon()

if ut == nil {

return nil

}

return ut.exportedMethods()

}

func (t *uncommonType) exportedMethods() []method {

if t.xcount == 0 {

return nil

}

return (*[1 《《 16]method)(add(unsafe.Pointer(t), uintptr(t.moff), “t.xcount 》 0”))[t.xcount]

}

ValueOf

func ValueOf(i interface{}) Value {

if i == nil {

return Value{}

}

// TODO: Maybe allow contents of a Value to live on the stack.

// For now we make the contents always escape to the heap. It

// makes life easier in a few places (see chanrecv/mapassign

// comment below)。

escapes(i)

return unpackEface(i)

}

func unpackEface(i interface{}) Value {

e := (*emptyInterface)(unsafe.Pointer(&i))

// NOTE: don‘t read e.word until we know whether it is really a pointer or not.

t := e.typ

if t == nil {

return Value{}

}

f := flag(t.Kind())

if ifaceIndir(t) {

f |= flagIndir

}

return Value{t, e.word, f}

}

value.Field

通過(guò) value 的 Field 可以獲取到結(jié)構(gòu)體的內(nèi)部屬性值,結(jié)構(gòu)體的內(nèi)部屬性都是 structField 類(lèi)型的,每個(gè) structField.offsetEmbed 是該屬性值距離結(jié)構(gòu)體地址的偏移量。

func (v Value) Field(i int) Value {

if v.kind() != Struct {

panic(&ValueError{“reflect.Value.Field”, v.kind()})

}

tt := (*structType)(unsafe.Pointer(v.typ))

if uint(i) 》= uint(len(tt.fields)) {

panic(“reflect: Field index out of range”)

}

field := &tt.fields[i]

typ := field.typ

// Inherit permission bits from v, but clear flagEmbedRO.

fl := v.flag&(flagStickyRO|flagIndir|flagAddr) | flag(typ.Kind())

// Using an unexported field forces flagRO.

if !field.name.isExported() {

if field.embedded() {

fl |= flagEmbedRO

} else {

fl |= flagStickyRO

}

}

// Either flagIndir is set and v.ptr points at struct,

// or flagIndir is not set and v.ptr is the actual struct data.

// In the former case, we want v.ptr + offset.

// In the latter case, we must have field.offset = 0,

// so v.ptr + field.offset is still the correct address.

ptr := add(v.ptr, field.offset(), “same as non-reflect &v.field”)

return Value{typ, ptr, fl}

}

type structField struct {

name name // name is always non-empty

typ *rtype // type of field

offsetEmbed uintptr // byte offset of field《《1 | isEmbedded

}

func (f *structField) offset() uintptr {

return f.offsetEmbed 》》 1

}

value.Method

我們從下面的代碼中可以看到,Method 也是返回一個(gè) Value,但是這個(gè) Value 的 ptr 并不是第 i 個(gè)函數(shù)的地址,而是原封不動(dòng)的將原 value 的 ptr 返回了,僅僅是對(duì) flag 設(shè)置比特位而已。

func (v Value) Method(i int) Value {

if v.typ == nil {

panic(&ValueError{“reflect.Value.Method”, Invalid})

}

if v.flag&flagMethod != 0 || uint(i) 》= uint(v.typ.NumMethod()) {

panic(“reflect: Method index out of range”)

}

if v.typ.Kind() == Interface && v.IsNil() {

panic(“reflect: Method on nil interface value”)

}

fl := v.flag & (flagStickyRO | flagIndir) // Clear flagEmbedRO

fl |= flag(Func)

fl |= flag(i)《《flagMethodShift | flagMethod

return Value{v.typ, v.ptr, fl}

}

value.Call

Call 函數(shù)目的是調(diào)用 value 的相應(yīng)的函數(shù),這里和 Method 是相互呼應(yīng)的,使用了 flag 的 flagMethodShift,得到了相應(yīng)的函數(shù)地址。

func (v Value) Call(in []Value) []Value {

v.mustBe(Func)

v.mustBeExported()

return v.call(“Call”, in)

}

func (v Value) call(op string, in []Value) []Value {

// Get function pointer, type.

t := (*funcType)(unsafe.Pointer(v.typ))

var (

fn unsafe.Pointer

rcvr Value

rcvrtype *rtype

if v.flag&flagMethod != 0 {

rcvr = v

rcvrtype, t, fn = methodReceiver(op, v, int(v.flag)》》flagMethodShift)

} else if v.flag&flagIndir != 0 {

fn = *(*unsafe.Pointer)(v.ptr)

} else {

fn = v.ptr

}

if fn == nil {

panic(“reflect.Value.Call: call of nil function”)

}

isSlice := op == “CallSlice”

n := t.NumIn()

if isSlice {

if !t.IsVariadic() {

panic(“reflect: CallSlice of non-variadic function”)

}

if len(in) 《 n {

panic(“reflect: CallSlice with too few input arguments”)

}

if len(in) 》 n {

panic(“reflect: CallSlice with too many input arguments”)

}

} else {

if t.IsVariadic() {

n--

}

if len(in) 《 n {

panic(“reflect: Call with too few input arguments”)

}

if !t.IsVariadic() && len(in) 》 n {

panic(“reflect: Call with too many input arguments”)

}

}

for _, x := range in {

if x.Kind() == Invalid {

panic(“reflect: ” + op + “ using zero Value argument”)

}

}

for i := 0; i 《 n; i++ {

if xt, targ := in[i].Type(), t.In(i); !xt.AssignableTo(targ) {

panic(“reflect: ” + op + “ using ” + xt.String() + “ as type ” + targ.String())

}

}

if !isSlice && t.IsVariadic() {

// prepare slice for remaining values

m := len(in) - n

slice := MakeSlice(t.In(n), m, m)

elem := t.In(n).Elem()

for i := 0; i 《 m; i++ {

x := in[n+i]

if xt := x.Type(); !xt.AssignableTo(elem) {

panic(“reflect: cannot use ” + xt.String() + “ as type ” + elem.String() + “ in ” + op)

}

slice.Index(i).Set(x)

}

origIn := in

in = make([]Value, n+1)

copy(in[:n], origIn)

in[n] = slice

}

nin := len(in)

if nin != t.NumIn() {

panic(“reflect.Value.Call: wrong argument count”)

}

nout := t.NumOut()

// Compute frame type.

frametype, _, retOffset, _, framePool := funcLayout(t, rcvrtype)

// Allocate a chunk of memory for frame.

var args unsafe.Pointer

if nout == 0 {

args = framePool.Get()。(unsafe.Pointer)

} else {

// Can’t use pool if the function has return values.

// We will leak pointer to args in ret, so its lifetime is not scoped.

args = unsafe_New(frametype)

}

off := uintptr(0)

// Copy inputs into args.

if rcvrtype != nil {

storeRcvr(rcvr, args)

off = ptrSize

}

for i, v := range in {

v.mustBeExported()

targ := t.In(i)。(*rtype)

a := uintptr(targ.align)

off = (off + a - 1) &^ (a - 1)

n := targ.size

if n == 0 {

// Not safe to compute args+off pointing at 0 bytes,

// because that might point beyond the end of the frame,

// but we still need to call assignTo to check assignability.

v.assignTo(“reflect.Value.Call”, targ, nil)

continue

}

addr := add(args, off, “n 》 0”)

v = v.assignTo(“reflect.Value.Call”, targ, addr)

if v.flag&flagIndir != 0 {

typedmemmove(targ, addr, v.ptr)

} else {

*(*unsafe.Pointer)(addr) = v.ptr

}

off += n

}

// Call.

call(frametype, fn, args, uint32(frametype.size), uint32(retOffset))

// For testing; see TestCallMethodJump.

if callGC {

runtime.GC()

}

var ret []Value

if nout == 0 {

typedmemclr(frametype, args)

framePool.Put(args)

} else {

// Zero the now unused input area of args,

// because the Values returned by this function contain pointers to the args object,

// and will thus keep the args object alive indefinitely.

typedmemclrpartial(frametype, args, 0, retOffset)

// Wrap Values around return values in args.

ret = make([]Value, nout)

off = retOffset

for i := 0; i 《 nout; i++ {

tv := t.Out(i)

a := uintptr(tv.Align())

off = (off + a - 1) &^ (a - 1)

if tv.Size() != 0 {

fl := flagIndir | flag(tv.Kind())

ret[i] = Value{tv.common(), add(args, off, “tv.Size() != 0”), fl}

// Note: this does introduce false sharing between results -

// if any result is live, they are all live.

// (And the space for the args is live as well, but as we‘ve

// cleared that space it isn’t as big a deal.)

} else {

// For zero-sized return value, args+off may point to the next object.

// In this case, return the zero value instead.

ret[i] = Zero(tv)

}

off += tv.Size()

}

}

return ret

}

原文標(biāo)題:Go interface 反射

文章出處:【微信公眾號(hào):Linux愛(ài)好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

責(zé)任編輯:haq

聲明:本文內(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

    文章

    8575

    瀏覽量

    151015
  • 發(fā)射
    +關(guān)注

    關(guān)注

    1

    文章

    93

    瀏覽量

    20859

原文標(biāo)題:Go interface 反射

文章出處:【微信號(hào):LinuxHub,微信公眾號(hào):Linux愛(ài)好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    反射內(nèi)存交換機(jī)工作原理

    天津拓航科技自研生產(chǎn)的反射內(nèi)存交換機(jī)工作原理解析
    的頭像 發(fā)表于 11-14 10:45 ?202次閱讀
    <b class='flag-5'>反射</b>內(nèi)存交換機(jī)<b class='flag-5'>工作</b>原理

    反射內(nèi)存卡的工作原理

    天津拓航科技反射內(nèi)存卡的工作原理
    的頭像 發(fā)表于 11-14 10:36 ?252次閱讀
    <b class='flag-5'>反射</b>內(nèi)存卡的<b class='flag-5'>工作</b>原理

    Golang配置代理方法

    由于一些客觀原因的存在,我們開(kāi)發(fā) Golang 項(xiàng)目的過(guò)程總會(huì)碰到無(wú)法下載某些依賴(lài)包的問(wèn)題。這不是一個(gè)小問(wèn)題,因?yàn)槟愕?b class='flag-5'>工作會(huì)被打斷,即便你使用各種神通解決了問(wèn)題,很可能這時(shí)你的線程已經(jīng)切換到其他的事情上了(痛恨思路被打斷!)。所以最好是一開(kāi)始我們就重視這個(gè)問(wèn)題,并一勞永逸
    的頭像 發(fā)表于 11-11 11:17 ?208次閱讀
    <b class='flag-5'>Golang</b>配置代理方法

    深度解析pci接口反射內(nèi)存卡

    天津拓航科技有限公司銷(xiāo)售國(guó)產(chǎn)自研反射內(nèi)存卡TH-PCI-210 兼容GE5565系列板卡 同時(shí)銷(xiāo)售GE反射內(nèi)存卡 全新未拆封
    的頭像 發(fā)表于 10-16 18:07 ?334次閱讀
    深度解析pci<b class='flag-5'>接口</b><b class='flag-5'>反射</b>內(nèi)存卡

    反射內(nèi)存卡工作環(huán)境介紹

    電子發(fā)燒友網(wǎng)站提供《反射內(nèi)存卡工作環(huán)境介紹.docx》資料免費(fèi)下載
    發(fā)表于 09-14 09:17 ?0次下載

    pci接口反射內(nèi)存卡

    pci反射內(nèi)存卡是一種用于實(shí)時(shí)網(wǎng)絡(luò)的硬件設(shè)備,他將反射內(nèi)存集成到卡上,通過(guò)計(jì)算機(jī)的PCI卡槽與計(jì)算機(jī)連接
    發(fā)表于 09-06 14:45 ?0次下載

    pcie接口反射內(nèi)存卡

    pci反射內(nèi)存卡是一種用于實(shí)時(shí)網(wǎng)絡(luò)的硬件設(shè)備,他將反射內(nèi)存集成到卡上,通過(guò)計(jì)算機(jī)的PCIe卡槽與計(jì)算機(jī)連接
    發(fā)表于 09-06 14:44 ?0次下載

    CPCI 接口反射內(nèi)存卡

    CPCI接口反射內(nèi)存卡是一種用于實(shí)時(shí)網(wǎng)絡(luò)的硬件設(shè)備,它將反射內(nèi)存集成在卡上,通過(guò)計(jì)算機(jī)的CPCI(CompactPCI)插槽與計(jì)算機(jī)連接。CPCI-5565PIORC是一款常見(jiàn)的CPCI接口
    的頭像 發(fā)表于 09-05 17:42 ?386次閱讀
    CPCI <b class='flag-5'>接口</b><b class='flag-5'>反射</b>內(nèi)存卡

    反射內(nèi)存卡工作環(huán)境

    反射內(nèi)存交換機(jī)作為一種專(zhuān)為高速、?實(shí)時(shí)數(shù)據(jù)交換而設(shè)計(jì)的網(wǎng)絡(luò)設(shè)備,?其工作環(huán)境具有特定的要求和應(yīng)用場(chǎng)景。?以下是對(duì)反射內(nèi)存交換機(jī)工作環(huán)境的詳細(xì)闡述:?
    的頭像 發(fā)表于 09-05 17:29 ?289次閱讀
    <b class='flag-5'>反射</b>內(nèi)存卡<b class='flag-5'>工作</b>環(huán)境

    PCIe 接口反射內(nèi)存卡

    PCIe接口反射內(nèi)存卡是一種用于實(shí)時(shí)網(wǎng)絡(luò)的硬件設(shè)備。它將反射內(nèi)存集成在卡上,通過(guò)PCIe(PCIExpress)總線與計(jì)算機(jī)進(jìn)行連接。反射內(nèi)存卡的主要作用是在多個(gè)獨(dú)立計(jì)算機(jī)之間實(shí)現(xiàn)高
    的頭像 發(fā)表于 09-04 10:38 ?431次閱讀
    PCIe <b class='flag-5'>接口</b>的<b class='flag-5'>反射</b>內(nèi)存卡

    PCI 接口反射內(nèi)存卡

    PCI接口反射內(nèi)存卡是一種用于實(shí)時(shí)網(wǎng)絡(luò)的硬件設(shè)備。它將反射內(nèi)存集成在卡上,通過(guò)計(jì)算機(jī)的PCI插槽與計(jì)算機(jī)連接。這種反射內(nèi)存卡具有以下特點(diǎn)和優(yōu)勢(shì):高速的光纖網(wǎng)絡(luò):提供高速數(shù)據(jù)傳輸,其光
    的頭像 發(fā)表于 09-04 10:36 ?363次閱讀
    PCI <b class='flag-5'>接口</b>的<b class='flag-5'>反射</b>內(nèi)存卡

    串行接口工作原理和結(jié)構(gòu)

    串行接口(Serial Interface)的工作原理和結(jié)構(gòu)是理解其在計(jì)算機(jī)與外部設(shè)備之間數(shù)據(jù)傳輸方式的重要基礎(chǔ)。以下將詳細(xì)闡述串行接口工作原理及其典型結(jié)構(gòu)。
    的頭像 發(fā)表于 08-25 17:01 ?1664次閱讀

    Golang為何舍棄三元運(yùn)算符

    golang中不存在?:運(yùn)算符的原因是因?yàn)檎Z(yǔ)言設(shè)計(jì)者已經(jīng)預(yù)見(jiàn)到三元運(yùn)算符經(jīng)常被用來(lái)構(gòu)建一些極其復(fù)雜的表達(dá)式。雖然使用if進(jìn)行替代會(huì)讓代碼顯得更長(zhǎng),但這毫無(wú)疑問(wèn)可讀性更強(qiáng)。
    的頭像 發(fā)表于 04-03 15:13 ?693次閱讀

    如何使用Golang連接MySQL

    首先我們來(lái)看如何使用Golang連接MySQL。
    的頭像 發(fā)表于 01-08 09:42 ?3337次閱讀
    如何使用<b class='flag-5'>Golang</b>連接MySQL

    如何使用SigXplorer進(jìn)行高速信號(hào)反射仿真

    在高速信號(hào)傳輸中,信號(hào)傳輸線上的反射是一個(gè)重要的問(wèn)題。當(dāng)信號(hào)從信號(hào)源發(fā)送到終端設(shè)備時(shí),信號(hào)在傳輸線上會(huì)遇到線路特性不連續(xù)的變化,如端口、接口或連接器的變化。這種變化導(dǎo)致信號(hào)的部分能量被反射回傳輸線中
    的頭像 發(fā)表于 12-23 08:12 ?2463次閱讀
    如何使用SigXplorer進(jìn)行高速信號(hào)<b class='flag-5'>反射</b>仿真
    RM新时代网站-首页