“區塊鏈是一門集合密碼學、共識演算法、智能合約、超級賬本等多門技術的複雜性綜合學科。”尹正表示,區塊鏈培訓機構的師資品質及其對區塊鏈行業的認知水平參差不齊,普通消費者也無從考究。
Go語言主要用作伺服器端開發,其定位是用來開發“大型軟體”的,適合於很多程式員一起開發大型軟體,並且開發週期長,支援雲端運算的網路服務。Go語言能夠讓程式員快速開發,並且在軟體不斷的增長過程中,它能讓程式員更容易地進行維護和修改。它融合了傳統編譯型語言的高效性和指令碼語言的易用性和富於表達性。
如果某個函數的入參是interface{},有下面幾種方式可以擷取入參的方法:
import "fmt"
func main() {
v := "hello world"
fmt.Println(typeof(v))
}
func typeof(v interface{}) string {
return fmt.Sprintf("%T", v)
}
2 反射:
import (
"reflect"
"fmt"
)
func main() {
v := "hello world"
fmt.Println(typeof(v))
}
func typeof(v interface{}) string {
return reflect.TypeOf(v).String()
}
3 類型斷言:
func main() {
v := "hello world"
fmt.Println(typeof(v))
}
func typeof(v interface{}) string {
switch t := v.(type) {
case int:
return "int"
case float64:
return "float64"
//... etc
default:
_ = t
return "unknown"
}
}
其實前兩個都是用了反射,fmt.Printf(“%T”)裡最終調用的還是reflect.TypeOf()。
func (p *pp) printArg(arg interface{}, verb rune) {
...
// Special processing considerations.
// %T (the value's type) and %p (its address) are special; we always do them first.
switch verb {
case 'T':
p.fmt.fmt_s(reflect.TypeOf(arg).String())
return
case 'p':
p.fmtPointer(reflect.ValueOf(arg), 'p')
return
}
reflect.TypeOf()的參數是v interface{},golang的反射是怎麼做到的呢?
在golang中,interface也是一個結構體,記錄了2個指標:
指標1,指向該變數的類型
指標2,指向該變數的value
如下,空介面的結構體就是上述2個指標,第一個指標的類型是type rtype struct;非空介面由於需要攜帶的資訊更多(例如該介面實現了哪些方法),所以第一個指標的類型是itab,在itab中記錄了該變數的動態類型: typ *rtype。
// emptyInterface is the header for an interface{} value.
type emptyInterface struct {
typ *rtype
word unsafe.Pointer
}
// nonEmptyInterface is the header for a interface value with methods.
type nonEmptyInterface struct {
// see ../runtime/iface.go:/Itab
itab *struct {
ityp *rtype // static interface type
typ *rtype // dynamic concrete type
link unsafe.Pointer
bad int32
unused int32
fun [100000]unsafe.Pointer // method table
}
word unsafe.Pointer
}
我們來看看reflect.TypeOf():
// TypeOf returns the reflection Type that represents the dynamic type of i.
// If i is a nil interface value, TypeOf returns nil.
func TypeOf(i interface{}) Type {
eface := *(*emptyInterface)(unsafe.Pointer(&i))
return toType(eface.typ)
}
TypeOf看到的是空介面interface{},它將變數的地址轉換為空白介面,然後將將得到的rtype轉為Type介面返回。需要注意,當調用reflect.TypeOf的之前,已經發生了一次隱式的類型轉換,即將具體類型的向空介面轉換。這個過程比較簡單,只要拷貝typ *rtype和word unsafe.Pointer就可以了。
例如w := os.Stdout,該變數的介面值在記憶體裡是這樣
那麼對於第三種,類型斷言是怎麼判斷是不是某個介面呢?回到最初,在golang中,介面是一個松耦合的概念,一個類型是不是實現了某個介面,就是看該類型是否實現了該介面要求的所有函數,所以,類型斷言判斷的方法就是檢查該類型是否實現了介面要求的所有函數。
走讀k8s代碼的時候,可以看到比較多的類型斷言的用法:
func LeastRequestedPriorityMap(pod *api.Pod, meta interface{}, nodeInfo *schedulercache.NodeInfo) (schedulerapi.HostPriority, error) {
var nonZeroRequest *schedulercache.Resource
if priorityMeta, ok := meta.(*priorityMetadata); ok {
nonZeroRequest = priorityMeta.nonZeroRequest
} else {
// We couldn't parse metadata - fallback to computing it.
nonZeroRequest = getNonZeroRequests(pod)
}
return calculateUnusedPriority(pod, nonZeroRequest, nodeInfo)
}
類型斷言的實現在src/runtime/iface.go裡(?),不過這塊代碼沒看懂,等以後再更新吧。
func assertI2I2(inter *interfacetype, i iface) (r iface, b bool) {
tab := i.tab
if tab == nil {
return
}
if tab.inter != inter {
tab = getitab(inter, tab._type, true)
if tab == nil {
return
}
}
r.tab = tab
r.data = i.data
b = true
return
}
func assertE2I2(inter *interfacetype, e eface) (r iface, b bool) {
t := e._type
if t == nil {
return
}
tab := getitab(inter, t, true)
if tab == nil {
return
}
r.tab = tab
r.data = e.data
b = true
return
}
高能預警,兄弟連教育區塊鏈直播課程8月持續火爆來襲!
原價1188元的12節區塊鏈進階課程,現僅需1元!
還可免費領取《Go語言基礎實戰項目開發》與《Go語言進階實戰項目開發》教材兩本!!
限時限量!!先到先得!!
http://www.ydma.cn/open/course/24
關注兄弟連區塊鏈公眾號可以獲得更多區塊鏈技術乾貨!!!