Golang底層原理剖析之method

2022-09-11 04:42:09 字數 1814 閱讀 6631

如果我們定義乙個型別a,並給它關聯乙個方法,然後就可以通過這個型別a的變數來呼叫這個方法了,這種呼叫方式其實是「語法糖」實際上和下面這種方式是一樣的。這裡變數a就是所謂的方法接收者,它會作為方法name的第乙個引數傳入。這一點我們可以通過右邊的**驗證一下,go中函式型別只和引數與返回值相關,所以這兩個型別值相等就能夠證明方法本質上就是普通的函式。而接收者就是隱含的第乙個引數。

下面來看看方法呼叫的情況,man函式棧幀區域性如圖,傳參值拷貝,函式內a.name指向新的字串內容,這裡的區域性變數a是值接收者,通過它呼叫方法時,修改的是拷貝過去的引數。而不是區域性變數a,要想修改區域性變數a,要用指標接收者。

把上面方法name的接收者改為指標型別,然後用pa來呼叫方法name。pa.name()會被轉換成(*a).name(pa)這樣的函式呼叫。傳參值拷貝,這裡拷貝的是區域性變數a的位址,修改的是區域性變數a。這就是指標接收者呼叫方法的過程,同樣要把接收者作為第乙個引數傳入。同樣是引數值拷貝,但是指標接收者拷貝的是位址,因此實現了對區域性變數a的修改。

這裡既有值接收者的方法,又有指標接收者的方法,我們已經了解了兩種接收者呼叫方法的基本過程,但是main函式中通過值呼叫指標接收者的方法,通過指標呼叫值接收者的方法。也能正常執行是什麼意思??其實若沒有涉及到介面的話,這些也是語法糖,編譯階段它會轉換成這種形式。不過既然這種語法糖在編譯期間發揮作用的,像編譯期間不能拿到位址的字面量是不能借助語法糖來轉換的,因此並不能通過編譯。

最後來看一下把乙個方法賦給乙個變數是怎麼回事,我們已經知道go中函式作為變數,引數和返回值時,都是以function value的形式存在的,也知道閉包只是有捕獲列表的function value而已。如果把乙個型別的方法賦給變數f1,f1就是乙個方法表示式。這實際上等價於f1:=getname,所以f1本質上也是乙個function value,也就是乙個funcval結構體的指標,fn指向a.getname的函式指令入口。 因為前面我們已經驗證了這兩個方法的等價性,所以通過f1執行方法時,需要傳入a型別的變數a作為第乙個引數,而f2:=a.getname以這樣的方式賦值,它被稱為方法變數,理論上講,方法變數也是乙個functionvalue,而且它會捕獲方法接收者, 形成閉包,但是這裡f2僅作為區域性變數,它與a的生命週期是一致的,所以編譯器會做出優化,把它轉換成型別a的方法呼叫並傳入a作為引數。

我們可以看乙個方法變數作為返回值的例子,對比一下。這裡f2與上個例子相同,它會被編譯器做出優化,而下面的f3賦值為getfunc函式的返回值,返回的是乙個方法變數,這等價於這樣一段**。通過這一段**我們可以清晰的看到閉包是如何形成的,所以這裡的f3就是乙個閉包物件,捕獲了getfunc函式的區域性變數a。

因此從本質上來講,方法表示式和方法變數都是function value

Volatile底層原理剖析

基礎知識回顧 還是那句話,無論語言再怎麼牛,其都是對底層計算機指令的封裝。計算機cpu執行指令的時候是非常快的,如果每執行乙個指令都從記憶體中取資料的話,那會非常慢,嚴重影響cpu的執行速度,所以每個cpu都有自身對應的高速緩衝區 多級暫存器 每個執行緒被執行的時候,會先把執行時需要的資料複製到告訴...

HashMap底層原理簡單剖析

1 hashmap的儲存結構 陣列 鍊錶 紅黑樹 jdk1.8 如下圖所示 2 hashmap的特點,如何實現 我們知道hashmap是一種可以快速儲存很快速查詢的鍵值容器,那麼jdk是如何實現hashmap的快速儲存和快速查詢呢?我們先從陣列和鍊錶以及二叉查詢樹這三種資料結構說起 1 陣列 陣列結...

深度剖析Spring Cloud底層原理

毫無疑問,spring cloud 是目前微服務架構領域的翹楚,無數的書籍部落格都在講解這個技術。不過大多數講解還停留在對 spring cloud 功能使用的層面,其底層的很多原理,很多人可能並不知曉。實際上,spring cloud 是乙個全家桶式的技術棧,它包含了很多元件。本文先從最核心的幾個...