Golangオブジェクト向け全解


Golangオブジェクト向け全解
golangのオブジェクト向けは不完全なオブジェクト向けで、大部分の人はjavaから変換され、多くのピットをもたらしました.この文章は私が知っているgolangのオブジェクト向けの性質とピットを記録しています.後者に注意してください.    
この文はただ個人が学習の過程の中で模索した自己総括で、完全に正しいことを理解することを保証することができなくて、もし間違いがあれば、指摘を歓迎して、共に学習します!
きそ
goにはclassの概念はなく、それに似たstruct構造体(c言語に似ている)だけで、インタフェースinterfaceもあります.
次に簡単に比較すると,彼は一般的な対象言語との概念的な違いである.
クラス/構造
インタフェース
go
struct構造体定義フェーズは、javaに及ばない可読性で、関数の前に識別子を追加することによって、メンバー変数の後にメソッドの記述を記述するしかない.
interfaceインタフェースはメソッドインタフェースのみを記述できます
java
classクラスはメンバー変数、メソッドを記述できます
interfaceインタフェースは、メンバーとメソッドインタフェースを記述できます.
定義上goのinterfaceは1つのタイプ定義としてのみ用いられ,メソッドの集合と考えることができ,structがどのインタフェースを継承して実装するかを明示的に宣言する必要はなく,まずそのメソッドを実装し,インタフェースに記述されたメソッドを実装したすべてのコンポーネントがこのインタフェースを実装したと考える.
この特性は非常に興味深いが,誤りやすいようで,我々がまだ実現していない方法を明示的に示すことはできない.
もう一つの特殊なインタフェースinterface{}は空のインタフェースと呼ばれ、中には0つの方法があり、すべてのオブジェクトが空のインタフェースを実現したと考えられています.
コード対比を行う前に,問題を説明するためにインタフェースタイプ判定の方法を導入する必要がある.
タイプ判定/変換
  • 変換
    a:=3
    float32(a)
    
    すべてのタイプ変換(後のタイプ変換と、関数パラメータ呼び出しで宣言されたタイプを含む)は、元のオブジェクトの頭文字の大文字のメンバー変数を呼び出すことができず、someInterfaceに記録されていないメソッドを呼び出すこともできません.つまり、someInterfaceに記録されているメソッドしか呼び出せません.
  • 列挙判断(既知のタイプで判断)
    switch interface{
           }(float32(3)).(type) {
           
    	case float32:
    		fmt.Prntln("this is float32")
    		
    	
    	}
    
    interface{
           }(3)//           
    
    注意、Object.(type)、Objectはinterface{}タイプである必要があり、interface{}は空のインタフェースを指し、すべてのオブジェクトがこのインタフェースを実現し、上記のタイプ変換を使用してオブジェクトをinterface{}タイプに変更することができる.この文法はswitchと協力する必要がある.
  • 型変換(インタフェースが実装されているか否かを判断するのによく用いられる)構文
    newObject,ok:=Object.(someType)
    
    では、Objectオブジェクトはinterface{}タイプであり、okは変換結果であり、true or false、newObjectは変換後のオブジェクトである.
  • golangのインタフェースと構造体
  • struct構造体
  • 構造体定義時にメンバー変数
  • しか記述できない.
  • メンバー変数は、アルファベットの大文字と小文字で公有と私有を区別し、アルファベットの大文字は公有変数であり、小文字は逆である.
  • 構造体タイプ宣言後、そのオブジェクトは、オブジェクトインスタンス
    type Person struct {
             
    	Name string
    }
    var p Person=Person{
             "Jack"}
    
  • を格納.
  • 構造体定義が完了すると、通常の関数に接頭辞を追加することによって、方法の定義と実現を完了することができる.
    //Person     
    //   
    func (p Person) say(){
             
      fmt.Println(p.Name)
    }
    //            ,  p Person     
    //
    //   
    func (p *Person) say(){
             
      fmt.Println(p.Name)
    }
    //  p Person     ,  p.Name      (*p).Name,go      ,        
    //                   ,          ,         
    

  • Interfaceインタフェース
  • インタフェースは、
  • を具体的に実装することなく、方法の説明のみを残すことができる.
  • インタフェースはメンバー変数
  • を記述できない.

    Goのオブジェクト向け実装
    まず,オブジェクト向けに3つの特性を有し,パッケージ,継承,マルチステート,goはいずれもこの3つの特性を直接サポートしないが,いずれも別の方法で実現できる.
    パッヶージ
    golangにはclassがなくstruct構造体のみで,クラス比c言語である.goのメンバー変数には、メンバー変数の変数名の先頭大文字と小文字によってアクセスを制御する権限修飾子、publicなどがありません.
    type Person struct {
         
    	Name string//    
      ago int//    
    }
    

    継承
    goでの継承は含むことによって実現される.
    2つのケースが含まれています.1つはjavaと同じように、父には息子の相手があり、息子と父はそれぞれ自分の名前を持っています.このときの息子と父は2つの異なるクラスに相当し、父には息子の相手があるだけです.
    package main
    
    import "fmt"
    
    type Person struct {
         
    	Name string
    }
    
    type Say interface {
         
    	say()
    }
    
    func (p *Person)say()  {
         
    	fmt.Println("My name is"+p.Name)
    }
    
    type Father struct {
         
    	son Person
    	Name string
    }
    
    func (f Father)teach()  {
         
    	fmt.Println("I am "+f.Name+", teaching my son"+f.son.Name)
    }
    
    func main() {
         
    	p:=Person{
         "Jack"}
    	f:=Father{
         p,"Tom"}
    	f.teach()
    }
    

    上はjavaの意味で含まれています.次はgoの継承を実現することを含むことによって、匿名のオブジェクトを転送することによって、親クラスのすべてのメンバー変数、方法がサブクラスになります.
    package main
    
    import "fmt"
    
    type Person struct {
         
    	Name string
    }
    
    type Say interface {
         
    	say()
    }
    
    func (p *Person)say()  {
         
    	fmt.Println("My name is "+p.Name)
    }
    
    type Teacher struct {
         
    	Person
    }
    
    func (f Teacher)teach()  {
         
    	fmt.Println("I am a teacher! And  My name is "+f.Name)
    }
    
    
    func main() {
         
    	t:=Teacher{
         Person{
         "Tom"}}
    	t.say()
    	t.teach()
    
    }
    

    マルチステート
    同じインタフェースが異なる実装では,この方法はgoでは鶏の肋骨を比較していると考えられる.
    package main
    
    import "fmt"
    
    type Person struct {
         
    	Name string
    }
    
    type Say interface {
         
    	say()
    }
    
    func (p Person)say()  {
         
    	fmt.Println("My name is "+p.Name)
    }
    
    type Teacher struct {
         
    	Name string
    }
    
    func (f Teacher)say()  {
         
    	fmt.Println("I am a teacher! And  My name is "+f.Name)
    }
    
    
    func main() {
         
    	var t,p Say =Teacher{
         "Tom"},Person{
         "Jack"}
    	
    	t.say()
    	p.say()
    
    
    }
    

    ピットポイント
  • インタフェース実装はプログラマーに直接知られず、ideに依存してプログラマーにこのインタフェースの方法が実装されていないことを伝えるしかない.
  • goインタフェースタイプオブジェクトに値を割り当てる場合、その参照またはインスタンスを受け入れることができます.
    package main
    
    import (
    	"fmt"
    )
    
    type Person struct {
           
    	Name string
    }
    
    type Say interface {
           
    	say()
    }
    
    func (p Person)say()  {
           
    	fmt.Println("My name is "+p.Name)
    }
    
    func main(){
           
      //       ,         ,                
      //             
    	//var p Say=&Person{"Tom"}
      var p Say=Person{
           "Tom"}
    	p.say()
    }
    
  • ideインタフェースが実装されているかどうかを判断し、定義された接頭辞の前に関数名の前に言及されたタイプに厳密に従ってアスタリスクを付けないで、区別がないように見えます.しかし、接頭辞にアスタリスクを付けた場合、
    //    
    func (p *Person)say()  {
           
    	fmt.Println("My name is "+p.Name)
    }
    
    func main(){
           
      //     
    	//var p Say=Person{"Tom"}
      //     
      var p Say=&Person{
           "Tom"}//new(Person)       ,     
    	p.say()
    }
    
    これは、ideがインタフェースが実装されているか否かを検出する際に、上記の定義タイプに厳格に従い、現在方法がPersonクラスのポインタに定義されているため、Personインスタンスは呼び出せないため、使用時にはポインタのみで呼び出すことができ、インタフェースオブジェクトを加えてポインタやインスタンスを受け入れることができるため、アドレス記号を付ける必要がある.上にアスタリスクがない場合は、メソッドがインスタンスに定義され、インスタンスとポインタが呼び出されます.しかし、いずれにしても、インタフェースインスタンスオブジェクトにアドレスシンボル&を付けると、必ず実行できます.インタフェースタイプに直接&
  • を追加することをお勧めします.
  • サブクラスは親メソッド上の異常
    package main
    
    import (
    	"fmt"
    )
    
    type Person struct {
           
    	Name string
    }
    
    //type Say interface {
           
    //	say()
    //}
    func (p *Person)call()  {
           
    	p.say()
    }
    
    func (p *Person)say()  {
           
    	fmt.Println("My name is "+p.Name)
    }
    
    type Teacher struct {
           
    	Person
    }
    
    func (t Teacher)say()  {
           
    	fmt.Println("I'm a teacher,"+t.Name)
    }
    
    
    
    func main(){
           
    	var t Teacher=Teacher{
           Person{
           "Tom"}}
    	t.call()
    }
    
    というコードを呼び出してpersonのsayを呼び出し、java上の結果とは異なり、これは反直感的である.実質的にはgoの関数呼び出しがタイプを厳格に守っているため,call関数の形式パラメータがpersonであるとteacherのsay関数が存在することを知らないため,personのsayを直接呼び出したと推測される.では、どうやって解決しますか?前にインタフェースは1種類の方法の集合であると言って、私たちは方法を呼び出す時、まず考えて、私たちはいったいどれだけの方法を必要として、この関数を構造体の外に剥離して、単独で1つの関数になって、形式のパラメータは必要な方法からなるインタフェースのオブジェクトを伝達して、以下の通りです:
    package main
    
    import (
    	"fmt"
    )
    
    type Person struct {
           
    	Name string
    }
    
    type Say interface {
           
    	say()
    }
    func call(s Say)  {
           
    	s.say()
    }
    
    func (p *Person)say()  {
           
    	fmt.Println("My name is "+p.Name)
    }
    
    type Teacher struct {
           
    	Person
    }
    
    func (t Teacher)say()  {
           
    	fmt.Println("I'm a teacher,"+t.Name)
    }
    
    
    
    func main(){
           
    	var t Teacher=Teacher{
           Person{
           "Tom"}}
    	call(t)
    }
    
    しかしすべての次男のクラスの方法が再ロードした後にすべて1つの外部の関数を書いて呼び出す必要があります.実際には面倒な場合がありますが、javaのような直接呼び出しリロードが可能なインタフェースを継承することで、メソッドを実装する際に、元のクラスのインスタンスを呼び出すのではなく、メソッドインタフェースのインスタンスを入力することで、継承可能な効果を書くことができることを考慮することができます.
    package main
    
    import (
    	"fmt"
    )
    
    type Person struct {
           
    	Name string
    }
    
    type Say interface {
           
    	say()
    }
    
    //                 ,            
    func (Person)call(s Say)  {
           
    	s.say()
    }
    
    func (p Person)say()  {
           
    	fmt.Println("My name is "+p.Name)
    }
    
    type Teacher struct {
           
    	Person
    }
    
    func (t Teacher)say()  {
           
    	fmt.Println("I'm a teacher,"+t.Name)
    }
    
    
    
    func main(){
           
    	var t Teacher=Teacher{
           Person{
           "Tom"}}
    	t.call(t)
    }
    
    どの方法もプログラマーの抽象能力に対してより高い要求を行い、プログラマーは方法内部でどの方法を呼び出す必要があるかを明確に知り、それによってそのインタフェースを抽象化する必要がある.エラーを恐れる場合は、継承関係のある構造体が実装されるときに、パラメータによってオブジェクトが渡されます.

  • golangのピットの多くはインターネット上にあり、これは私たちが通常のオブジェクト向け言語を勉強した後に残された状況で、go公式はgoでオブジェクトに向かうことをあまり提案していないと聞いていますが、オブジェクト向けは確かに効率を高めることができます.私たちはgoの中でこれまでの対象思考でそれを見ることができません.