GO語言學習筆記(與Java的比較學習)(八)

接口與反射

接口是什么

Go 語言不是一種 “傳統” 的面向對象編程語言:它里面沒有類和繼承的概念。

但是 Go 語言里有非常靈活的 接口 概念,通過它可以實現很多面向對象的特性。接口提供了一種方式來 說明 對象的行為:如果誰能搞定這件事,它就可以用在這兒。

接口定義了一組方法(方法集),但是這些方法不包含(實現)代碼:它們沒有被實現(它們是抽象的)。接口里也不能包含變量。

通過如下格式定義接口:

type Namer interface {Method1(param_list) return_typeMethod2(param_list) return_type...
}

不像大多數面向對象編程語言,在 Go 語言中接口可以有值,一個接口類型的變量或一個 接口值 :var ai Namer,ai 是一個多字(multiword)數據結構,它的值是 nil。它本質上是一個指針,雖然不完全是一回事。指向接口值的指針是非法的,它們不僅一點用也沒有,還會導致代碼錯誤。

類型(比如結構體)實現接口方法集中的方法,每一個方法的實現說明了此方法是如何作用于該類型的:即實現接口,同時方法集也構成了該類型的接口。實現了 Namer 接口類型的變量可以賦值給 ai (接收者值),此時方法表中的指針會指向被實現的接口方法。當然如果另一個類型(也實現了該接口)的變量被賦值給 ai,這二者(譯者注:指針和方法實現)也會隨之改變

  • 類型不需要顯式聲明它實現了某個接口:接口被隱式地實現。多個類型可以實現同一個接口。

  • 實現某個接口的類型(除了實現接口方法外)可以有其他的方法。

  • 一個類型可以實現多個接口。

  • 接口類型可以包含一個實例的引用, 該實例的類型實現了此接口(接口是動態類型)。

?
package main
?
import "fmt"
?
type Sharper interface {Area() float32
}
?
type Square struct {side float32
}
?
func (sq *Square) Area() float32 {return sq.side * sq.side
}
?
func main() {sq := new(Square)sq.side = 6
?var area Sharperarea = sqfmt.Printf("the result is %f", area.Area())
}?

接口嵌套接口

type ReadWrite interface {Read(b Buffer) boolWrite(b Buffer) bool
}
?
type Lock interface {Lock()Unlock()
}
?
type File interface {ReadWriteLockClose()
}

一個接口類型的變量 varI 中可以包含任何類型的值,必須有一種方式來檢測它的 動態 類型,即運行時在變量中存儲的值的實際類型。在執行過程中動態類型可能會有所不同,但是它總是可以分配給接口變量本身的類型。通常我們可以使用 類型斷言 來測試在某個時刻 varI 是否包含類型 T 的值:

v := varI.(T) ? ? ? // unchecked type assertion

更安全的方式是使用以下形式來進行類型斷言:

if v, ok := varI.(T); ok { ?// checked type assertionProcess(v)return
}
// varI is not of type T

類型判斷:type-switch

switch t := areaIntf.(type) {
case *Square:fmt.Printf("Type Square %T with value %v\n", t, t)
case *Circle:fmt.Printf("Type Circle %T with value %v\n", t, t)
case nil:fmt.Printf("nil value: nothing to check?\n")
default:fmt.Printf("Unexpected type %T\n", t)
}

測試一個值是否實現了某個接口

type Stringer interface {String() string
}
?
if sv, ok := v.(Stringer); ok {fmt.Printf("v implements String(): %s\n", sv.String()) // note: sv, not v
}

空接口

概念

空接口或者最小接口 不包含任何方法,它對實現不做任何要求:

type Any interface {}

任何其他類型都實現了空接口(它不僅僅像 Java/C# 中 Object 引用類型),any 或 Any 是空接口一個很好的別名或縮寫。

空接口類似 Java/C# 中所有類的基類: Object 類,二者的目標也很相近。

可以給一個空接口類型的變量 var val interface {}賦任何類型的值。

package main
?
import "fmt"
?
var i = 5
var str = "ABC"
?
type Person struct {name stringage ?int
}
?
type Any interface{}
?
func main() {var val Anyval = 5fmt.Printf("val has the value: %v\n", val)val = strfmt.Printf("val has the value: %v\n", val)pers1 := new(Person)pers1.name = "Rob Pike"pers1.age = 55val = pers1fmt.Printf("val has the value: %v\n", val)switch t := val.(type) {case int:fmt.Printf("Type int %T\n", t)case string:fmt.Printf("Type string %T\n", t)case bool:fmt.Printf("Type boolean %T\n", t)case *Person:fmt.Printf("Type pointer to Person %T\n", t)default:fmt.Printf("Unexpected type %T", t)}
}

反射包

方法和類型的反射

變量的最基本信息就是類型和值:反射包的 Type 用來表示一個 Go 類型,反射包的 Value 為 Go 值提供了反射接口。

兩個簡單的函數,reflect.TypeOf 和 reflect.ValueOf,返回被檢查對象的類型和值。例如,x 被定義為:var x float64 = 3.4,那么 reflect.TypeOf(x) 返回 float64,reflect.ValueOf(x) 返回 <float64 Value>

通過反射修改 (設置) 值

package main
?
import ("fmt""reflect"
)
?
func main() {var x float64 = 3.4v := reflect.ValueOf(x)// setting a value:// v.SetFloat(3.1415) // Error: will panic: reflect.Value.SetFloat using unaddressable valuefmt.Println("settability of v:", v.CanSet())v = reflect.ValueOf(&x) // Note: take the address of x.fmt.Println("type of v:", v.Type())fmt.Println("settability of v:", v.CanSet())v = v.Elem()fmt.Println("The Elem of v is: ", v)fmt.Println("settability of v:", v.CanSet())v.SetFloat(3.1415) // this works!fmt.Println(v.Interface())fmt.Println(v)
}

反射結構體

package main
?
import ("fmt""reflect"
)
?
type NotknownType struct {s1, s2, s3 string
}
?
func (n NotknownType) String() string {return n.s1 + " - " + n.s2 + " - " + n.s3
}
?
// variable to investigate:
var secret interface{} = NotknownType{"Ada", "Go", "Oberon"}
?
func main() {value := reflect.ValueOf(secret) // <main.NotknownType Value>typ := reflect.TypeOf(secret) ? ?// main.NotknownType// alternative://typ := value.Type()  // main.NotknownTypefmt.Println(typ)knd := value.Kind() // structfmt.Println(knd)
?// iterate through the fields of the struct:for i := 0; i < value.NumField(); i++ {fmt.Printf("Field %d: %v\n", i, value.Field(i))// error: panic: reflect.Value.SetString using value obtained using unexported field//value.Field(i).SetString("C#")}
?// call the first method, which is String():results := value.Method(0).Call(nil)fmt.Println(results) // [Ada - Go - Oberon]
}

接口與動態類型

Go 的動態類型

Go 沒有類:數據(結構體或更一般的類型)和方法是一種松耦合的正交關系。

Go 中的接口跟 Java/C# 類似:都是必須提供一個指定方法集的實現。但是更加靈活通用:任何提供了接口方法實現代碼的類型都隱式地實現了該接口,而不用顯式地聲明。

動態方法調用

Go 的實現通常需要編譯器靜態檢查的支持:當變量被賦值給一個接口類型的變量時,編譯器會檢查其是否實現了該接口的所有函數。如果方法調用作用于像 interface{} 這樣的 “泛型” 上,你可以通過類型斷言來檢查變量是否實現了相應接口。

顯式地指明類型實現了某個接口

如果你希望滿足某個接口的類型顯式地聲明它們實現了這個接口,你可以向接口的方法集中添加一個具有描述性名字的方法。例如:

type Fooer interface {Foo()ImplementsFooer()
}
空接口和函數重載

在 Go 語言中函數重載可以用可變參數 ...T 作為函數最后一個參數來實現。如果我們把 T 換為空接口,那么可以知道任何類型的變量都是滿足 T (空接口)類型的,這樣就允許我們傳遞任何數量任何類型的參數給函數,即重載的實際含義。

接口的繼承

當一個類型包含(內嵌)另一個類型(實現了一個或多個接口)的指針時,這個類型就可以使用(另一個類型)所有的接口方法。

類型可以通過繼承多個接口來提供像 多重繼承 一樣的特性

Go 中的面向對象

Go 沒有類,而是松耦合的類型、方法對接口的實現。

OO 語言最重要的三個方面分別是:封裝,繼承和多態,在 Go 中它們實現如下:

  • 封裝(數據隱藏):和別的 OO 語言有 4 個或更多的訪問層次相比,Go 把它簡化為了 2 層(導出和不可導出)

    • 包范圍內的:通過標識符首字母小寫,對象 只在它所在的包內可見

    • 可導出的:通過標識符首字母大寫,對象 對所在包以外也可見

  • 繼承:用組合實現:內嵌一個(或多個)包含想要的行為(字段和方法)的類型;多重繼承可以通過內嵌多個類型實現

  • 多態:用接口實現:某個類型的實例可以賦給它所實現的任意接口類型的變量。類型和接口是松耦合的,并且多重繼承可以通過實現多個接口實現。Go 接口不是 Java 和 C# 接口的變體,而且:接口間是不相關的,并且是大規模編程和可適應的演進型設計的關鍵。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/717977.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/717977.shtml
英文地址,請注明出處:http://en.pswp.cn/news/717977.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

springer模板參考文獻不顯示

Spring期刊模板網站&#xff0c;我的問題是23年12月的版本 https://www.springernature.com/gp/authors/campaigns/latex-author-support/see-where-our-services-will-take-you/18782940 參考文獻顯示問好&#xff0c;在sn-article.tex文件中&#xff0c;這個sn-mathphys-num…

數據結構c版(3)——排序算法

本章我們來學習一下數據結構的排序算法&#xff01; 目錄 1.排序的概念及其運用 1.1排序的概念 1.2 常見的排序算法 2.常見排序算法的實現 2.1 插入排序 2.1.1基本思想&#xff1a; 2.1.2直接插入排序&#xff1a; 2.1.3 希爾排序( 縮小增量排序 ) 2.2 選擇排序 2.2…

rtt的io設備框架面向對象學習-io設備管理層

目錄 1.設備基類2.rtt基類2.1 rtt基類定義2.2 對象容器定義2.3 rtt基類構造函數 3.io設備管理接口4.總結 這層我的理解就是rtt基類和設備基類所在&#xff0c;所以抽離出來好點&#xff0c;不然每個設備類都要重復它。 1.設備基類 /include/rtdef.h中定義了設備基類struct rt_…

記錄踩過的坑-PyTorch

安裝報錯 按PyTorch官網給出的命令 pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 報錯 ERROR: Could not find a version that satisfies the requirement torch (from versions: none) ERROR: No matching distributio…

Redis為什么這么快?

基于內存&#xff1a;Redis 將數據存儲在內存中&#xff0c;內存訪問速度遠高于磁盤訪問速度&#xff0c;因此能夠快速讀寫數據。單線程模型&#xff1a;Redis 使用單線程模型來處理客戶端請求&#xff0c;避免了多線程之間的切換開銷&#xff0c;簡化了并發控制&#xff0c;提…

STM32(11)按鍵產生中斷

1.初始化IO引腳&#xff0c;設置模式&#xff0c;速度等 2.設置AFIO&#xff08;配置EXTI的引腳映射&#xff09;&#xff0c;記得開啟時鐘 3.配置EXTI的通道&#xff08;EXTI0和EXTI1&#xff09; 4.配置NVIC 4.1 中斷優先級分組 4.2 配置中斷 5.編寫中斷響應函數 在中斷向量…

消息隊列的實現

8.8 消息隊列 隊列是一種先進先出的結構&#xff0c;消息隊列是進程(線程)常用的一種方法&#xff0c;實現消息隊列常用的方法&#xff1a; &#xff08;1&#xff09;阻塞隊列 &#xff08;2&#xff09;無鎖隊列 &#xff08;3&#xff09;環形隊列 值得注意的是&#xff…

藍橋ACM培訓-實戰1

前言&#xff1a; 今天老師沒講課&#xff0c;只讓我們做了一下幾道題目。 正文&#xff1a; Problem:A 小藍與操作序列&#xff1a; #include<bits/stdc.h> using namespace std; stack<int> a; int main(){int n,flag1,ans;string cz;cin>>n;for(int i1;…

訪問修飾符、Object(方法,使用、equals)、查看equals底層、final--學習JavaEE的day15

day15 一、訪問修飾符 含義&#xff1a; 修飾類、方法、屬性&#xff0c;定義使用的范圍 理解&#xff1a;給類、方法、屬性定義訪問權限的關鍵字 注意&#xff1a; ? 1.修飾類只能使用public和默認的訪問權限 ? 2.修飾方法和屬性可以使用所有的訪問權限 訪問修飾符本類本包…

JetCache源碼解析——API實現(持續更新中……)

在JetCache中不僅可以通過在類和接口的函數上使用注解Cached、CacheUpdate和CacheInvalidate等實現緩存加載、更新和刪除操作&#xff0c;也支持通過調用API接口的形式來實現緩存的加載、更新和刪除操作。 緩存接口 緩存接口的定義如下&#xff1a; /*** 緩存接口&#xff0…

【計算機網絡】HTTPS 協議原理

https 一、HTTPS 是什么二、加密1. 加密概念2. 加密的原因3. 常見的加密方式&#xff08;1&#xff09;對稱加密&#xff08;2&#xff09;非對稱加密 三、數據摘要(數據指紋)四、HTTPS 的工作原理探究1. 只使用對稱加密2. 只使用非對稱加密3. 雙方都使用非對稱加密4. 非對稱加…

Linux:kubernetes(k8s)部署CNI網絡插件(4)

在上一章進行了node加入master Linux&#xff1a;kubernetes&#xff08;k8s&#xff09;node節點加入master主節點&#xff08;3&#xff09;-CSDN博客https://blog.csdn.net/w14768855/article/details/136420447?spm1001.2014.3001.5501 但是他們顯示還是沒準備好 看一下…

面試筆記系列五之MySql+Mybaits基礎知識點整理及常見面試題

目錄 Myibatis myibatis執行過程 mybatis的優缺點有哪些&#xff1f; mybatis和hibernate有什么區別&#xff1f; mybatis中#{}和${}的區別是什么&#xff1f; 簡述一下mybatis插件運行原理及開發流程&#xff1f;&#xff08;插件四大天王&#xff09; mybatis的mapper沒…

2.模擬問題——5.星期幾與字符串對應

輸入輸出示例 輸入&#xff1a; 9 October 2001 14 October 2001 輸出&#xff1a; Tuesday Sunday 【原題鏈接】 字符串處理 C風格的字符串 字符數組&#xff0c;以’\0‘結尾建議在輸入輸出語句中使用 C風格的字符串 #include <string> using namespace std;初始化…

「優選算法刷題」:最長回文子串

一、題目 給你一個字符串 s&#xff0c;找到 s 中最長的回文子串。 如果字符串的反序與原始字符串相同&#xff0c;則該字符串稱為回文字符串。 示例 1&#xff1a; 輸入&#xff1a;s "babad" 輸出&#xff1a;"bab" 解釋&#xff1a;"aba"…

【字符串】馬拉車(Manacher)算法

本篇文章參考&#xff1a;比較易懂的 Manacher&#xff08;馬拉車&#xff09;算法配圖詳解 馬拉車算法可以求出一個字符串中的最長回文子串&#xff0c;時間復雜度 O ( n ) O(n) O(n) 因為字符串長度的奇偶性&#xff0c;回文子串的中心可能是一個字符&#xff0c;也可能是…

uniapp聊天記錄本地存儲(詳細易懂)

目錄 目錄 1、通過websocket拿取數據 2、獲取聊天數據 3、聊天信息存儲 、更新 4、讀取聊天記錄 5、發送信息&#xff0c;信息獲取 6、最終效果 1.聊天信息的存儲格式 2、樣式效果 寫聊天項目&#xff0c;使用到了本地存儲。需要把聊天信息保存在本地&#xff0c;實時獲…

GPT對話知識庫——ARM-Cortex架構分為哪幾個系列?每個系列有幾種工作模式?各種工作模式之間的定義和區別?每種架構不同的特點和應用需求?

提問模型&#xff1a;GPT-4-TURBO-PREVIEW 提問時間&#xff1a;2024.03.02 1&#xff0c;問&#xff1a; Cortex-M系列有幾種工作模式 1&#xff0c;答&#xff1a; Cortex-M系列微控制器是ARM公司開發的一類低功耗、高性能的32位微處理器&#xff0c;廣泛應用于嵌入式系統中…

Centos7使用man查找命令時,報錯No manual entry for xxxx

Centos7使用man查找命令時&#xff0c;報錯No manual entry for xxxx 在Linux中使用man指令查找指令信息時&#xff0c;報No manual entry for xxxx。 比如使用man指令查找sleep3號手冊時&#xff0c;出現以下錯誤&#xff1a; 這是由于沒有安裝man-pages這個rpm包導致的&#…

掌握基本排序算法:冒泡、選擇、插入和快速排序

在計算機科學的世界里&#xff0c;排序是一項基本而重要的操作。無論是數據庫管理、搜索引擎&#xff0c;還是日常編程&#xff0c;高效的排序算法都是提高性能的關鍵。本文將介紹四種基本的排序算法&#xff1a;冒泡排序、選擇排序、插入排序和快速排序&#xff0c;并探討它們…