關於重載,重寫,覆蓋的基本概念要分清楚,
Go中確實是不支持重載的, 官方給出的解釋是
其他語言的經驗告訴我們,有各種同名但簽名不同的方法有時是有用的,但在實踐中也可能令人困惑。關於重載運算符,似乎更方便,但是同樣的,沒有重載會更簡單。
因此這么設計的目的其實 使Go語言保持簡單 這一核心目標
而關於重寫和覆蓋,emmm,筆者自己的理解是,畢竟不是真正的繼承,而是復合。並且也不能像繼承一樣用父類定義而使用子類的實例充當具體實現,所以這個問題其實是不存在的?
畢竟 var cat Pet = new(Cat) 是會報錯的,沒有繼承又何談重寫或覆蓋呢?
關於這一部分的代碼測試例子如下:
package extension
import (
"testing"
"fmt"
)
type Pet struct{
}
func (p *Pet) Speak() {
fmt.Print("In Pet ...")
}
// Go中不支持重載 以下代碼會提示錯誤:
/*
method redeclared: Pet.Speak
method(*Pet) func()
method(*Pet) func() stringgo
*/
// func (p *Pet) Speak() string {
// fmt.Print("In Pet ...")
// return "Try to overload"
// }
func (p *Pet) SpeakTo(host string) {
p.Speak()
fmt.Println("In Pet ", host)
}
type Dog struct {
p *Pet
}
func (d *Dog) Speak() {
fmt.Print("In Dog ...")
d.p.Speak()
}
func (d *Dog) SpeakTo(host string) {
d.Speak()
fmt.Println("In Dog ", host)
d.p.SpeakTo(host)
}
type Cat struct{
Pet
}
func (c *Cat) Speak() {
fmt.Print("Try to overwrite Miao")
}
func TestDog(t *testing.T){
dog := new(Dog)
dog.SpeakTo("Hello")
//注意上面是復合不是集成
//注意還有Go中的匿名嵌套方法,感覺上像是繼承
/*
type Cat struct {
Pet
}
*/
cat := new(Cat)
cat.SpeakTo("Miao")
//輸出結果是In Pet ...In Pet Miao(Pet中的方法)
//可以通過
var cat1 *Pet = new(Pet)
//下面一行會提示錯誤:cannot use new(Cat) (type *Cat) as type *Pet in assignmentgo
//var cat1 *Pet = new(Cat)
cat1.Speak()
//不同的寫法也是一樣的
//可以通過
var cat2 Pet = Pet{}
//提示錯誤:cannot use Cat literal (type Cat) as type Pet in assignment
//var cat2 Pet = Cat{}
cat2.Speak()
}
輸出結果為:
=== RUN TestDog
In Dog ...In Pet ...In Dog Hello
In Pet ...In Pet Hello
In Pet ...In Pet Miao
In Pet ...In Pet ...--- PASS: TestDog (0.00s)
=== RUN TestPolymorphism
*extension.GoProgrammer, fmt.Println("Hello World!")
extension.JavaProgrammer, System.out.Println("Hello World!")
--- PASS: TestPolymorphism (0.00s)
PASS
coverage: [no statements]
ok Session12/extension 0.276s coverage: [no statements]
關於DuckType還有一些補充內容:
package extension
import (
"testing"
"fmt"
)
type Code string
type Programmer interface{
WriteHelloWorld() Code
//ReadHelloWorld() Code
//上面這個ReadHelloWorld() Code是一個實驗
/*
如果一個接口沒有實現接口的全部方法會怎樣呢?
如果我們在接口里定義了ReadHelloWorld() Code這個方法,即使后面我們完全沒有用到它
仍然會在build時提示錯誤:cannot use goProg (type *GoProgrammer) as type Programmer in argument to writeFirstProgram:
*GoProgrammer does not implement Programmer (missing ReadHelloWorld method)
也就是說,雖然有Duck Type的存在,但如果一個結構沒有實現接口的全部方法,那么這個結構就不能作為這個接口的實現。
*/
}
type GoProgrammer struct{
}
func (p *GoProgrammer) WriteHelloWorld() Code {
return "fmt.Println(\"Hello World!\")"
}
type JavaProgrammer struct{
}
func (p JavaProgrammer) WriteHelloWorld() Code {
return "System.out.Println(\"Hello World!\")"
}
func writeFirstProgram(p Programmer){
fmt.Printf("%T, %v\n", p, p.WriteHelloWorld())
}
func TestPolymorphism(t *testing.T){
goProg := new(GoProgrammer)
javaProg := JavaProgrammer{}
writeFirstProgram(goProg)
writeFirstProgram(javaProg)
//Interface不只能傳遞指針類型,而是根據實例有沒有實現interface的方法,例如上面的javaProg
//例如上面如果把 JavaProgram中的WriteHelloWorld方法定義更改為:func (p *JavaProgrammer) WriteHelloWorld() Code
//則會提示錯誤:cannot use javaProg (type JavaProgrammer) as type Programmer in argument to writeFirstProgram:
//JavaProgrammer does not implement Programmer (WriteHelloWorld method has pointer receiver)
}
總結一下就是,雖然有DuckType存在,不需要繼承自接口, 但如果一個結構沒有實現接口的全部方法,它仍然不能看作是這個接口的實現。
另外Interface能不能傳遞指針類型,主要看實例實現接口時的方式。
