本節讀書筆記對應原書第六章。 在函式宣告時,在其名字之前放上乙個變數,就是乙個方法。
package geometry
import
"math"
type point struct
func
(p point)
distance
(q point)
float64
func
distance
(q,p point)
float64
這裡提供了兩個distance
,第乙個distance
就是乙個方法,附加的引數p
是方法的接收器,表示distance
屬於point
這種型別的獨有方法,第二個distance
就是乙個傳統的函式。早期的說法:呼叫乙個方法稱為向乙個物件傳送訊息。
我們可以任意選擇接收器的名字,但建議接收器的名字要統一和簡短,此外,一般是不適用this
或者self
作為接收器的。
下面看一下這兩種方式如何被使用的。
p:=point
q:=point
fmt.
println
(distance
(p,q)
)//使用包級別的函式distance
fmt.
println
(p.distance
(q))
//使用point類下生命的point.distance方法
這裡多說一句,如果在包外呼叫的時候,使用方法會比函式更簡短,因為呼叫包級別的函式需要寫包名,舉個例子。
import
"gopl.io/ch6/geometry"
perim := geometry.path,,
,}fmt.
println
(geometry.path.
distance
(perim)
)// "12", standalone function
fmt.
println
(perim.
distance()
)// "12", method of geometry.path
總結:
當呼叫乙個函式的時候,會對其每乙個引數值進行拷貝,如果乙個函式需要更新乙個變數,或者函式的其中乙個引數實在太大,那麼應使用指標來宣告方法。
type point2 struct
func
(p *point2)
scaleby
(factor float64
)
該方法的名字就是(*point).scaleby。如果point2
這個類有乙個指標作為接收器的方法,那麼所有point2
的方法都必須有乙個指標接收器,即使是那些並不需要這個指標接收器的函式。如果乙個型別本身就是乙個指標的話,那是不能出現在接收器中的,就像下面這樣會出現compile error
。
type p *
intfunc
(p)f()
呼叫指標型別方法有3種方法,以呼叫指標型別方法(*point2).scaleby為例:
//first
r :=
&point2
r.scaleby(2
)fmt.
println
(*r)
// ""
//second
p := point2
pptr :=
&ppptr.
scaleby(2
)fmt.
println
(p)// ""
//third
p := point2
(&p)
.scaleby(2
)fmt.
println
(p)// ""
其實還有簡短的寫法:
p:= point2
p.scaleby(2
)
編譯器會隱式用&p
呼叫scaleby
方法,不過這種簡寫只適合變數。不能通過乙個無法取到位址的接收器(比如臨時變數的記憶體位址)來呼叫指標方法。
point
.scaleby(2
)// compile error
注意:
import
"image/color"
type point struct
type coloredpoint struct
func
(p point)
distance
(q point)
float64
point這個型別嵌入到coloredpoint來提供x和y這兩個字段 ,可以把coloredpoint型別當作接收器來呼叫point裡的方法,point類的方法也被引入了coloredpoint 。
distance有乙個引數是point型別, 但q雖然有point這個內嵌型別,但它並不是point
型別,使用時要顯式地選擇。
p.
distance
(q)// compile error: cannot use q (coloredpoint) as point
p.distance
(q.point)
//right
結構體中也可以內嵌乙個型別的指標,這種情況下字段和方法會被間接引入到當前型別中,訪問的時候通過這個指標指向的物件去取。
type coloredpoint struct
p:= coloredpoint
, red}
q := coloredpoint
, blue}
fmt.
println
(p.distance
(*q.point)
)// "5"
q.point = p.point // p and q now share the same point
p.scaleby(2
)fmt.
println
(*p.point,
*q.point)
// " "
p := point
q := point
distancefromp := p.distance // method value
fmt.
println
(distancefromp
(q))
fmt.
println
(p.distance
(q))
為了說明這兩個概念,還是先看個例子。我們呼叫乙個方法一般採用p.distance(q)
形式一步到位,但實際上等價於兩步,首先將選擇器返回的方法值儲存到乙個變數中distancefromp := p.distance
,這其實是將方法繫結到特定接收器變數的函式,然後呼叫時直接傳入引數就可以了distancefromp(q)
。和之前的方式比,似乎少了乙個接收器p
,其實我們之前已經指定過了。
下面說方法表示式,方法表示式就是剛剛的p.distance
,方法表示式返回的是方法值。如果t是乙個型別,方法表示式可能寫作t.f或者(*t).f
,如何使用方法表示式最合適呢?
使用方法表示式,可以根據選擇來呼叫接收器各不相同的方法。如下所示,我們可以為path陣列中的每乙個point來呼叫對應的sub或者add方法。
type point struct
func
(p point)
add(q point) point
}func
(p point)
sub(q point) point
}type path [
]point
func
(path path)
translateby
(offset point, add bool
)else
for i :=
range path
}
初學c 讀書筆記(五) 方法A
1 方法結構 方法是一塊具有名稱的 可以使用方法名執行 也可以把資料傳入方法並接收資料輸出。方法的特徵 方法是否返回資料,如果返回,返回什麼型別 方法名什麼型別的輸入可以傳入方法 方法體包含可以執行 的語句序列。intsum intvar1,intvar2 2 本地變數 本地變數用於儲存本地的或臨時...
初學c 讀書筆記(五) 方法C
12 棧幀 當乙個方法被呼叫時,在棧頂分配了一塊記憶體用於儲存一定數量與方法相關的資料項,這塊記憶體叫方法的棧幀 棧幀儲存以下資訊 返回位址 分配記憶體的引數 與方法呼叫相關的其他各種管理資料項 方法被呼叫時,它的整個棧幀被壓入棧中 方法退出時,它的整個棧幀被從棧中彈出 class program ...
初學c 讀書筆記(五) 方法B
6 引數 形參因為形參是變數,所以有型別和名稱,並能寫入和讀取 形參在方法體的外面定義並在方法開始之前初始化 引數列表中可以有人一數目的形參,使用逗號隔開 實參用於初始化形參的表示式或變數稱為實參 實參放在方法呼叫的引數列表中 實參的數目與形引數目相同,且型別相匹配 7 值引數 使用值引數,資料通過...