ゴーチュートリアルシリーズ - インターフェイス19(B)

ようこそ  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 型は  EmployeeOperationse 型がされ  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]

これは、プレゼンテーション・インタフェースを終了します。私はあなたが幸せにしたいです。

おすすめ

転載: www.cnblogs.com/fengchuiyizh/p/11349809.html