Go語言-為什麼返回值為接口類型,卻返回結構體

最近由於項目需求,閱讀一些Go語言編寫的項目的源代碼,在某一個函數中發現瞭一個奇怪的現象:一個函數的返回值類型聲明的是一個接口的類型,但是實際在函數體內返回的卻是一個結構體類型的對象。

這個現象對於新手的我來說很是費解。在經過一些資料的查閱之後,自己得到瞭如下的解釋:

一個結構體實現瞭一個接口,那麼函數中返回值類型為接口時,就應該返回這個結構體。

下面舉一個例子來說明:

package main
import (
	"fmt"
)
/**
Shape接口定義兩個函數:
area() :計算面積
circumference() :計算周長
*/
type Shape interface {
	area() float64
	circumference() float64
}
//結構體正方形,屬性邊長
type square struct {
	length float64
}
//方法area,由正方形結構體實現
func (s square) area()  float64 {
	sarea := s.length * s.length
	return sarea
}
//方法circumference,由正方形結構體實現
func (s square) circumference()  float64 {
	scircumference := s.length * 4
	return scircumference
}
func getarea(len float64) Shape {
	s := square{
		length:4,
	}
	fmt.Println("正方形的面積為:",s.area())
	fmt.Println("正方形的周長為:",s.circumference())
	return s
}
func main() {
	getarea(4)
}

或者另一個版本:

package main
import (
	"fmt"
)
/**
Shape接口定義兩個函數:
area() :計算面積
circumference() :計算周長
*/
type Shape interface {
	area() float64
	circumference() float64
}
//結構體正方形,屬性邊長
type square struct {
	length float64
}
//方法area,由正方形結構體實現
func (s *square) area()  float64 {
	sarea := s.length * s.length
	return sarea
}
//方法circumference,由正方形結構體實現
func (s *square) circumference()  float64 {
	scircumference := s.length * 4
	return scircumference
}
func getarea(len float64) Shape {
	s := &square{
		length:4,
	}
	fmt.Println("正方形的面積為:",s.area())
	fmt.Println("正方形的周長為:",s.circumference())
	return s
}
func main() {
	getarea(4)
}

這兩個代碼的區別就是前者使用瞭值傳遞,後者使用瞭指針傳遞。由於這裡沒有改變結構體中的屬性值,所以兩種方法在這樣的應用場景下,沒有什麼區別,下面來解釋一下這些簡單的demo:

首先我定義瞭一個Shape接口,裡面有兩個待實現的方法area() :計算面積 和 circumference() :計算周長

然後定義瞭一個正方形結構體,裡面隻有一個邊長屬性。

然後使用正方形結構體實現這個Shape接口

接著我們就可以進入正題,試驗我們標題的問題瞭,使用Shape接口類型作為返回值,但是在函數體內實際的返回值是正方形結構體。

這是Go的一種語法,但實際的作用或者為是什麼這樣寫,我還沒有弄清楚,但是通過以上這個實實在在的例子,關於為什麼返回值類型和實際返回的不一樣有瞭一定的理解。

補充:Go語言-結構體和接口

結構體和接口

接口嵌套

接口中允許嵌套其他接口,效果等同於復制被嵌套的接口中的方法

當前的接口中不允許有與嵌入的接口相同的方法

方法相同的接口相等同

接口不能為空,否則等同於空接口

結構體嵌套

結構體中的匿名成員內的成員和方法會被嵌套到當前結構體中

當前結構體中允許有與被嵌套結構體相同的成員和方法,且會覆蓋被嵌套的結構體的成員和方法

兩個被嵌套的結構體有相同的成員或方法,會發生沖突

有時候編輯器不會提示,但會產生運行時錯誤

成員名稱和類型完全相同的結構體

如果其中一個是匿名的,可以直接賦值或判斷相等

類型名不同可以進行類型轉換,不可以直接賦值或判斷相等

方法的接收器隻能是在當前包中指定名稱的類型,不能是原生類型、復合類型、其他包中的類型

重新命名的結構體與原結構體成員完全相同(包括tag),但是沒有原來的方法

接口實現

一個類型實現瞭接口的所有方法,就是實現瞭接口,不管類型和接口之間是否有關聯

方法的接收器可以是這個類型或者這個類型的指針類型

指針類型的接收器可以被修改成員

非指針類型的實例直接調用指針類型接收器的方法,會遇到無法調用指針方法,無法獲取地址的問題

指針類型的實例調用非指針類型接收器的方法不會出現問題

將實例賦值給變量再調用不會出現問題

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。如有錯誤或未考慮完全的地方,望不吝賜教。

推薦閱讀: