ようこそ Golangチュートリアルシリーズ 19のチュートリアルの。2つのチュートリアルがありますインターフェイス、これは私たちの第二のチュートリアルです。あなたは前のチュートリアルを読んでいない場合は、読みのインターフェイスを(A) 。
インタフェースを実装:受信者と受信者のポインタ値を
インタフェース(a)は実施例の全てで、我々は、レシピエント(受信値)の値を使用して、インタフェースを実装することです。我々はまた、レシピエント(ポインタ受信機)のインタフェースポインタを使用して実施することができます。しかし、受信者のインタフェースポインタの実現に、注意を必要とするいくつかの詳細があります。私たちは、コードに従うことによって理解する必要があります。
package main
import "fmt" type Describer interface { Describe() } type Person struct { name string age int } func (p Person) Describe() { // 使用值接受者实现 fmt.Printf("%s is %d years old\n", p.name, p.age) } type Address struct { state string country string } func (a *Address) Describe() { // 使用指针接受者实现 fmt.Printf("State %s Country %s", a.state, a.country) } func main() { var d1 Describer p1 := Person{"Sam", 25} d1 = p1 d1.Describe() p2 := Person{"James", 32} d1 = &p2 d1.Describe() var d2 Describer a := Address{"Washington", "USA"} /* 如果下面一行取消注释会导致编译错误: cannot use a (type Address) as type Describer in assignment: Address does not implement Describer (Describe method has pointer receiver) */ //d2 = a d2 = &a // 这是合法的 // 因为在第 22 行,Address 类型的指针实现了 Describer 接口 d2.Describe() }
上記手順のライン13は、構造体 Person
レシピエントの値を使用して、実装する Describer
インターフェイスを。
私たちは話しているメソッドを呼び出すために、ポインタを使用しても、すでに言及した際、呼び出すためにどちらかの値によって、受信者の方法宣言された値を使用して。値、または可能な解決策のポインタ参照は、そのようなメソッドを呼び出すかどうかは合法です。
p1
タイプがあり Person
、ライン29でp1
に割り当てられました d1
。そのため Person
、インタフェース変数を実装し d1
、そのライン30には、それが印刷されます Sam is 25 years old
。
ライン32において、次に、d1
割り当てられた &p2
ライン33と同じプリントアウト上で、 James is 32 years old
。バンバンの騒々し。:)
22行目では、構造体の Address
ポインタ受信機を実装 Describer
インタフェースを。
上記のプログラムでは、非コメント行45場合、我々は、コンパイルエラーになります:main.go:42: cannot use a (type Address) as type Describer in assignment: Address does not implement Describer (Describe method has pointer receiver)
。ライン22において、我々が使用するためである Address
ポインタ型受信機がインタフェースを実装 Describer
し、次に我々が試み a
割り当てます d2
。しかし、 a
タイプに属する値は、それが実装されていない Describer
インターフェイスを。私たちは、ポインタの受信者の使用して、学んできたので、あなたは、非常に驚いあるべき方法を関係なく、ポインタの値の、またはそれを呼び出すことができます。なぜ作品の最初の45行をコードしないのですか?
理由:コールの値を取得するためのポインタまたはアドレスと、ポインタの受信者を使用するための方法が合法です。しかし、特定の値(具体的な値は)インターフェイスに格納されたアドレスを取ることができないので、ライン45は、コンパイラが自動的に取得できない a
アドレスを、ルーチンが与えられます。
私たちは、ライン47を正常に実行することができ a
、アドレス &a
に割り当てられています d2
。
プログラムの他の部分は自明です。プログラムが印刷されます:
Sam is 25 years old
James is 32 years old
State Washington Country USA
複数のインターフェースを実装
タイプは、複数のインタフェースを実装することができます。ここでは、手順がどのように行われるかを参照してください。
package main
import ( "fmt" ) type SalaryCalculator interface { DisplaySalary() } type LeaveCalculator interface { CalculateLeavesLeft() int } type Employee struct { firstName string lastName string basicPay int pf int totalLeaves int leavesTaken int } func (e Employee) DisplaySalary() { fmt.Printf("%s %s has salary $%d", e.firstName, e.lastName, (e.basicPay + e.pf)) } func (e Employee) CalculateLeavesLeft() int { return e.totalLeaves - e.leavesTaken } func main() { e := Employee { firstName: "Naveen", lastName: "Ramanathan", basicPay: 5000, pf: 200, totalLeaves: 30, leavesTaken: 5, } var s SalaryCalculator = e s.DisplaySalary() var l LeaveCalculator = e fmt.Println("\nLeaves left =", l.CalculateLeavesLeft()) }
上記の手順では、ライン7とライン11は、それぞれ二つのインターフェースを宣言:SalaryCalculator
および LeaveCalculator
。
ライン15は、構造規定する Employee
第二の行24実装し、 SalaryCalculator
インタフェース DisplaySalary
ライン28に続く方法、および実装 LeaveCalculator
におけるインターフェース CalculateLeavesLeft
方法を。だから、 Employee
実現されている SalaryCalculator
と LeaveCalculator
二つのインターフェース。
ライン41は、我々はしている e
に割り当てられた SalaryCalculator
インタフェース変数の種類、およびライン43に、我々は同じき e
に割り当てられた LeaveCalculator
インタフェース変数のタイプ。理由 e
のタイプの Employee
器具 SalaryCalculator
と LeaveCalculator
二つのインターフェース、これは合法です。
プログラムが出力されます:
Naveen Ramanathan has salary $5200
Leaves left = 25
ネストされたインターフェース
ゴー言語は継承メカニズムを提供していませんが、他のインターフェイスは、新しいインターフェイスを作成するために、入れ子にすることができますが。
私たちは、これを実現する方法を見て。
package main
import ( "fmt" ) type SalaryCalculator interface { DisplaySalary() } type LeaveCalculator interface { CalculateLeavesLeft() int } type EmployeeOperations interface { SalaryCalculator LeaveCalculator } type Employee struct { firstName string lastName string basicPay int pf int totalLeaves int leavesTaken int } func (e Employee) DisplaySalary() { fmt.Printf("%s %s has salary $%d", e.firstName, e.lastName, (e.basicPay + e.pf)) } func (e Employee) CalculateLeavesLeft() int { return e.totalLeaves - e.leavesTaken } func main() { e := Employee { firstName: "Naveen", lastName: "Ramanathan", basicPay: 5000, pf: 200, totalLeaves: 30, leavesTaken: 5, } var empOp EmployeeOperations = e empOp.DisplaySalary() fmt.Println("\nLeaves left =", empOp.CalculateLeavesLeft()) }
15行のプログラムでは、我々は新しいインターフェイスを作成し EmployeeOperations
、それが二つのインタフェースを入れ子にしていますSalaryCalculator
と LeaveCalculator
。
タイプが定義されている場合 SalaryCalculator
や LeaveCalculator
インタフェースに含まれるメソッド、我々はタイプが実装されていることを言う EmployeeOperations
のインターフェイスを。
以来、ライン29とライン33において、 Employee
構造が定義されている DisplaySalary
と CalculateLeavesLeft
方法は、インタフェースを実装します EmployeeOperations
。
46行では、empOp
型は EmployeeOperations
、e
型がされ Employee
、我々は、 empOp
割り当てられました e
。次の2行は、empOp
呼ば DisplaySalary()
および CalculateLeavesLeft()
方法。
プログラムを印刷:
Naveen Ramanathan has salary $5200
Leaves left = 25
インタフェースのゼロ値
インタフェースのゼロ値です nil
。値のための nil
インターフェースの基礎となる値(基礎値)と、特定のタイプ(コンクリートタイプ)です nil
。
package main
import "fmt" type Describer interface { Describe() } func main() { var d1 Describer if d1 == nil { fmt.Printf("d1 is nil and has type %T value %v\n", d1, d1) } }
上記プログラム d1
等しい nil
、プログラム意志出力:
d1 is nil and has type <nil> value <nil>
値のために nil
、我々はそのメソッドを呼び出すしようとすると、インターフェイスの、とボトム値の特定のタイプが存在しない場合、プログラムが生成されます panic
例外を。
package main
type Describer interface { Describe() } func main() { var d1 Describer d1.Describe() }
上記の手順では、d1
等しい nil
、プログラム実行時エラー panic
: panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0xffffffff addr=0x0 pc=0xc8527]
。
これは、プレゼンテーション・インタフェースを終了します。私はあなたが幸せにしたいです。