GO-接口

1. 接口

在Go語言中接口(interface)是一種類型,一種抽象的類型。

interface是一組method的集合,接口做的事情就像是定義一個協議(規則),只要一臺機器有洗衣服和甩干的功能,我就稱它為洗衣機。不關心屬性(數據),只關心行為(方法)。

接口(interface)是一種類型

接口類型是對其它類型行為的抽象和概括;因為接口類型不會和特定的實現細節綁定在一起,通過這種抽象的方式我們可以讓我們的函數更加靈活和更具有適應能力。

接口是雙方約定的一種合作協議。接口實現者不需要關心接口會被怎樣使用,調用者也不需要關心接口的實現細節。接口是一種類型,也是一種抽象結構,不會暴露所含數據的格式、類型及結構。

1.2 接口定義

Go語言提倡面向接口編程。

每個接口類型由數個方法組成。接口的形式代碼如下:

type 接口類型名 interface{方法名1( 參數列表1 ) 返回值列表1方法名2( 參數列表2 ) 返回值列表2…
}

對各個部分的說明:

  • 接口類型名:使用 type 將接口定義為自定義的類型名。Go語言的接口在命名時,一般會在單詞后面添加 er,如有寫操作的接口叫 Writer,有字符串功能的接口叫 Stringer,有關閉功能的接口叫 Closer 等。
  • 方法名:當方法名首字母是大寫時,且這個接口類型名首字母也是大寫時,這個方法可以被接口所在的包(package)之外的代碼訪問。
  • 參數列表、返回值列表:參數列表和返回值列表中的參數變量名可以被忽略
type Writer interface {//接口名和方法首字母大寫,意味著可以被其他包訪問Write([]byte)string
}

1.3 接口實現條件

如果一個任意類型 T 的方法集為一個接口類型的方法集的超集,則我們說類型 T 實現了此接口類型。

T 可以是一個非接口類型,也可以是一個接口類型。

實現關系在Go語言中是隱式的。兩個類型之間的實現關系不需要在代碼中顯式地表示出來。Go語言中沒有類似于 implements 的關鍵字。 Go編譯器將自動在需要的時候檢查兩個類型之間的實現關系。

接口定義后,需要實現接口,調用方才能正確編譯通過并使用接口。

接口的實現需要遵循兩條規則才能讓接口可用:

  1. 接口的方法與實現接口的類型方法格式一致在類型中添加與接口簽名一致的方法就可以實現該方法。簽名包括方法中的名稱、參數列表、返回參數列表。也就是說,只要實現接口類型中的方法的名稱、參數列表、返回參數列表中的任意一項與接口要實現的方法不一致,那么接口的這個方法就不會被實現。
// 定義一個數據寫入器
type DataWriter interface {Write(interface{}) error
}// 定義文件結構,用于實現DataWriter
type file struct {
}// 實現DataWriter接口的WriteData方法
func (f *file) Write(b interface{}) error {return fmt.Sprintf("writer:", b)
}func main() {// 實例化filef := new(file)// 聲明一個DataWriter的接口var write DataWriter// 將接口賦值f,也就是*file類型write = f// 使用DataWriter接口進行數據寫入write.Write("hhhhhhhh")
}
  1. 當類型無法實現接口時,編譯器會報錯:
    1. 函數名不一致導致的報錯
    2. 實現接口的方法簽名不一致導致的報錯
  1. 接口中所有方法均被實現當一個接口中有多個方法時,只有這些方法都被實現了,接口才能被正確編譯并使用。

// 定義一個數據寫入器
type DataWriter interface {Write(interface{}) error//上述代碼中新增一個方法Content() bool
}

運行結果

.\main.go:28:10: cannot use f (variable of type *file) as DataWriter value in assignment: *file does not implement DataWriter (missing method Content)

Go語言的接口實現是隱式的,無須讓實現接口的類型寫出實現了哪些接口。

這個設計被稱為非侵入式設計。

1.4 類型與接口的關系

在Go語言中類型和接口之間有一對多和多對一的關系

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

一個類型可以同時實現多個接口,而接口間彼此獨立,不知道對方的實現。

例如,狗可以叫,也可以動。

我們就分別定義Sayer接口和Mover接口,如下:

type Sayer interface {Say()
}type Mover interface {Move()
}type Dog struct {name string
}// dog實現say和move接口
func (d Dog) Say() {fmt.Println(d.name, " saying......")
}func (d Dog) Move() {fmt.Println(d.name, "moving ......")
}func main() {var x Sayervar y Movervar dog = Dog{"wangwang"}x = dogy = dogx.Say()  //wangwang  saying......y.Move() //wangwang moving ......}

多個類型實現同一接口

type Mover interface {Move()
}type Dog struct {name string
}type Car struct {name string
}//dog 和 car都實現mover接口func (d Dog) Move() {fmt.Println(d.name, "moving,....")
}func (c Car) Move() {fmt.Println(c.name, "moving .....")
}func main() {var d = Dog{"旺財"}var c = Car{"小米"}var move Movermove = dmove.Move() //旺財 moving,....move = cmove.Move() //小米 moving .....}

接口嵌套

接口與接口間可以通過嵌套創造出新的接口

// Sayer 接口
type Sayer interface {say()
}// Mover 接口
type Mover interface {move()
}// 接口嵌套
type animal interface {SayerMover
}

嵌套得到的接口的使用與普通接口一樣,這里我們讓cat實現animal接口:

type cat struct {name string
}func (c cat) say() {fmt.Println("喵喵喵")
}func (c cat) move() {fmt.Println("貓會動")
}func main() {var x animalx = cat{name: "花花"}x.move()x.say()
}

1.5 空接口

空接口是指沒有定義任何方法的接口。

因此任何類型都實現了空接口。

空接口類型的變量可以存儲任意類型的變量。

func main() {var x interface{}var i = 100x = ifmt.Println(x) //100var name = "hhhhh"x = namefmt.Println(x)  //hhhhh
}

1.5.1 空接口的應用

空接口作為函數的參數

使用空接口實現可以接收任意類型的函數參數。

func show(a interface{}) {fmt.Println(a)
}func main() {//空接口作為函數參數show("空接口傳參")  //空接口傳參}

空接口作為map的值

使用空接口實現可以保存任意值的字典。

func main() {var student = make(map[string]interface{}, 3)student["小明"] = 100student["小紅"] = "hahah"student["小高"] = falsefmt.Printf("%+v", student)  //map[小明:100 小紅:hahah 小高:false]}

1.5.2 類型斷言

空接口可以存儲任意類型的值,那我們如何獲取其存儲的具體數據呢?

接口值

一個接口的值(簡稱接口值)是由一個具體類型和具體類型的值兩部分組成的。

這兩部分分別稱為接口的動態類型和動態值。

想要判斷空接口中的值這個時候就可以使用類型斷言,其語法格式:

x.(T)

1

其中:

  1. x:表示類型為interface{}的變量
  2. T:表示斷言x可能是的類型。

該語法返回兩個參數,第一個參數是x轉化為T類型后的變量,第二個值是一個布爾值,若為true則表示斷言成功,為false則表示斷言失敗。

func main() {var student = make(map[string]interface{}, 3)student["小明"] = 100student["小紅"] = "hahah"student["小高"] = falsefmt.Printf("%+v\n", student) //map[小明:100 小紅:hahah 小高:false]_, ok := student["小明"].(bool)if ok != true {fmt.Println("student[\"小明\"]不是bool")  }
}

2. I/O操作

I/O操作也叫輸入輸出操作。其中I是指Input,O是指Output,用于讀或者寫數據的,有些語言中也叫流操作,是指數據通信的通道。

Golang 標準庫對 IO 的抽象非常精巧,各個組件可以隨意組合,可以作為接口設計的典范。

io包中提供I/O原始操作的一系列接口。

它主要包裝了一些已有的實現,如 os 包中的那些,并將這些抽象成為實用性的功能和一些其他相關的接口。

由于這些接口和原始的操作以不同的實現包裝了低級操作,客戶不應假定它們對于并行執行是安全的。

io庫比較常用的接口有三個,分別是Reader,Writer和Closer。

2.1 Reader

Reader接口的定義,Read()方法用于讀取數據。

type Reader interface {Read(p []byte) (n int, err error)
}

io.Reader 表示一個讀取器,它將數據從某個資源讀取到傳輸緩沖區。在緩沖區中,數據可以被流式傳輸和使用。

  • 對于要用作讀取器的類型,它必須實現 io.Reader 接口的唯一一個方法 Read(p []byte)。
  • 換句話說,只要實現了 Read(p []byte) ,那它就是一個讀取器。
  • Read() 方法有兩個返回值,一個是讀取到的字節數,一個是發生錯誤時的錯誤。

通過 string.NewReader(string) 創建一個字符串讀取器,然后流式地按字節讀取:


func main() {reader := strings.NewReader("this is a reader")// 每次讀取4個字節p := make([]byte, 4)for {n, err := reader.Read(p)if err != nil {if err == io.EOF {log.Println("讀完了")break}log.Fatalln("read error", err)os.Exit(2)}log.Println("讀取到的字節數:", n)}}
  • 最后一次返回的 n 值有可能小于緩沖區大小。
  • io.EOF 來表示輸入流已經讀取到頭

2.1.1 文件操作相關API
func Create(name string) (file *File, err Error)

1

    • 根據提供的文件名創建新的文件,返回一個文件對象,默認權限是0666
func NewFile(fd uintptr, name string) *File

1

    • 根據文件描述符創建相應的文件,返回一個文件對象
func Open(name string) (file *File, err Error)

1

    • 只讀方式打開一個名稱為name的文件
func OpenFile(name string, flag int, perm uint32) (file *File, err Error)

1

    • 打開名稱為name的文件,flag是打開的方式,只讀、讀寫等,perm是權限
func (file *File) Write(b []byte) (n int, err Error)

1

    • 寫入byte類型的信息到文件
func (file *File) WriteAt(b []byte, off int64) (n int, err Error)

1

    • 在指定位置開始寫入byte類型的信息
func (file *File) WriteString(s string) (ret int, err Error)

1

    • 寫入string信息到文件
func (file *File) Read(b []byte) (n int, err Error)

1

    • 讀取數據到b中
func (file *File) ReadAt(b []byte, off int64) (n int, err Error)

1

    • 從off開始讀取數據到b中
func Remove(name string) Error

1

    • 刪除文件名為name的文件
2.1.2 讀文件

type Closer interface {Close() error
}

os.Open()函數能夠打開一個文件,返回一個*File和一個err。對得到的文件實例調用Close()方法能夠關閉文件。

文件讀取可以用file.Read(),讀到文件末尾會返回io.EOF的錯誤

func main() {// 打開文件file, err := os.Open("C:\\Users\\Administrator\\Desktop\\新建 文本文檔 (2).txt")if err != nil {log.Println("打開失敗")}defer file.Close()// 定義接收文件讀取的字節數組buff := make([]byte, 128)var content []bytefor {_, err := file.Read(buff)if err == io.EOF {log.Println("讀完了")break}if err != nil {log.Println("讀取失敗:", err)return}}content = append(content, buff...)fmt.Sprintln(content)
}

Writer

type Writer interface {//Write() 方法有兩個返回值,一個是寫入到目標資源的字節數,一個是發生錯誤時的錯誤。Write(p []byte) (n int, err error)
}

  • io.Writer 表示一個寫入器,它從緩沖區讀取數據,并將數據寫入目標資源。
  • 對于要用作編寫器的類型,必須實現 io.Writer 接口的唯一一個方法 Write(p []byte)
  • 同樣,只要實現了 Write(p []byte) ,那它就是一個編寫器。
func main() {// 打開文件file, err := os.Open("C:\\Users\\Administrator\\Desktop\\新建 文本文檔 (2).txt")if err != nil {log.Println("打開失敗")}defer file.Close()// 定義接收文件讀取的字節數組buff := make([]byte, 128)var content []bytefor {_, err := file.Read(buff[:])if err == io.EOF {log.Println("讀完了")break}if err != nil {log.Println("讀取失敗:", err)return}}content = append(content, buff...)fmt.Println(string(content))
}

2.2 Writer

type Writer interface {//Write() 方法有兩個返回值,一個是寫入到目標資源的字節數,一個是發生錯誤時的錯誤。Write(p []byte) (n int, err error)
}
  • io.Writer 表示一個寫入器,它從緩沖區讀取數據,并將數據寫入目標資源。
  • 對于要用作編寫器的類型,必須實現 io.Writer 接口的唯一一個方法 Write(p []byte)
  • 同樣,只要實現了 Write(p []byte) ,那它就是一個編寫器。

寫文件:

func main() {file, err := os.Create("test.txt")if err != nil {log.Println("create error")}defer file.Close()b := make([]byte, 0)for i := 0; i < 10; i++ {b = append(b, byte(i))}file.WriteString(string(b))
}

2.3 bufio

  • bufio包實現了帶緩沖區的讀寫,是對文件讀寫的封裝
  • bufio緩沖寫數據

模式

含義

os.O_WRONLY

只寫

os.O_CREATE

創建文件

os.O_RDONLY

只讀

os.O_RDWR

讀寫

os.O_TRUNC

清空

os.O_APPEND

追加

bufio讀寫數據

func wr() {// 參數2:打開模式,所有模式d都在上面// 參數3是權限控制// w寫 r讀 x執行   w  2   r  4   x  1//特殊權限位,擁有者位,同組用戶位,其余用戶位file, err := os.OpenFile("./xxx.txt", os.O_CREATE|os.O_WRONLY, 0666)if err != nil {return}defer file.Close()// 獲取writer對象writer := bufio.NewWriter(file)for i := 0; i < 10; i++ {writer.WriteString("hello\n")}// 刷新緩沖區,強制寫出writer.Flush()
}func re() {file, err := os.Open("./xxx.txt")if err != nil {return}defer file.Close()reader := bufio.NewReader(file)for {line, _, err := reader.ReadLine()if err == io.EOF {break}if err != nil {return}fmt.Println(string(line))}}func main() {re()
}


2.5 實現一個cat命令

使用文件操作相關知識,模擬實現linux平臺cat命令的功能。

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

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

相關文章

【go語言開發】swagger安裝和使用

本文主要介紹go-swagger的安裝和使用&#xff0c;首先介紹如何安裝swagger&#xff0c;測試是否成功&#xff1b;然后列出常用的注釋和給出使用例子&#xff1b;最后生成接口文檔&#xff0c;并在瀏覽器上測試 文章目錄 安裝注釋說明常用注釋參考例子 文檔生成格式化文檔生成do…

C++從零開始的打怪升級之路(day39)

這是關于一個普通雙非本科大一學生的C的學習記錄貼 在此前&#xff0c;我學了一點點C語言還有簡單的數據結構&#xff0c;如果有小伙伴想和我一起學習的&#xff0c;可以私信我交流分享學習資料 那么開啟正題 今天分享的是關于模板的知識點 1.非類型模板參數 模板參數分為…

大模型生成,Open API調用

大模型是怎么生成結果的 通俗原理 其實&#xff0c;它只是根據上文&#xff0c;猜下一個詞&#xff08;的概率&#xff09;…… OpenAI 的接口名就叫【completion】&#xff0c;也證明了其只會【生成】的本質。 下面用程序演示【生成下一個字】。你可以自己修改 prompt 試試…

高并發下的 AtomicReference 性能陷阱

介紹 Java 提供了 AtomicInteger/AtomicLong 在并發編程里經常用到&#xff0c;它們封裝了對 int 和 long 的原子操作。 Java 還提供了 AtomicReference&#xff0c;用于對象引用做原子性的管理&#xff0c;比如 get、set、CAS。 一般情況下 AtomicInteger、AtomicLong 的性能…

mac新環境

1、maven 設置阿里云鏡像 打開Maven的settings.xml文件。找到<mirrors>標簽&#xff0c;如果沒有&#xff0c;可以手動添加。在<mirrors>標簽內部添加以下內容&#xff1a; <mirror> <id>nexus-aliyun</id> <mirrorOf>*</mirrorO…

【C++】類的轉換函數

使用場景 C中當你創建了一個類&#xff0c;你想把這個類對象轉換成基本類型的函數。類對象->基本類型對象 原理 如下實例&#xff0c;設計一個分數類&#xff0c;實現分數轉換成double 浮點數的轉換函數。并在mian函數隱式調用。 #include<iostream> class Fractio…

6. 使用 Spring Boot進行開發(Developing with Spring Boot)

6. 使用 Spring Boot進行開發&#xff08;Developing with Spring Boot&#xff09; 本節詳細介紹了如何使用Spring Boot。它涵蓋考慮構建系統、自動配置以及如何運行應用程序等主題。我們還介紹一些 Spring Boot 最新做法。雖然 Spring Boot 沒有什么特別之處&#xff08;它只…

Java 接口和抽象類有何區別?

Java接口&#xff08;Interface&#xff09;和抽象類&#xff08;Abstract Class&#xff09;都是面向對象編程中用于實現多態和代碼復用的重要概念&#xff0c;但它們之間有幾個關鍵的區別&#xff1a; 1. **實例化**&#xff1a; - **接口**&#xff1a;不能被實例化。它…

【Spring連載】使用Spring Data訪問 MongoDB----對象映射之JSON Schema

【Spring連載】使用Spring Data訪問 MongoDB----對象映射之JSON Schema 一、生成Schema二、加密字段三、JSON Schema類型 從3.6版本開始&#xff0c;MongoDB支持根據提供的 JSON Schema驗證documents的集合。在創建集合時&#xff0c;可以定義schema本身以及驗證操作和級別&…

Python爬蟲Cookies 池的搭建

Cookies 池的搭建 很多時候&#xff0c;在爬取沒有登錄的情況下&#xff0c;我們也可以訪問一部分頁面或請求一些接口&#xff0c;因為畢竟網站本身需要做 SEO&#xff0c;不會對所有頁面都設置登錄限制。 但是&#xff0c;不登錄直接爬取會有一些弊端&#xff0c;弊端主要有…

南京師范大學計電院數據結構課設——排序算法

1 排序算法 1.1 題目要求 編程實現希爾、快速、堆排序、歸并排序算法。要求首先隨機產生10000個數據存入磁盤文件&#xff0c;然后讀入數據文件&#xff0c;分別采用不同的排序方法進行排序并將結果存入文件中。 1.2 算法思想描述 1.2.1 隨機數生成 當需要生成一系列隨機數…

windows 11 前后端項目部署

目錄 1.準備環境&#xff1a; 2.安裝jdk 測試&#xff1a;winr 輸入cmd 3.安裝tomcat 4.安裝mysql 遠程導入數據&#xff1a; 外部后臺訪問&#xff1a;192.168.232.1:8080/crm/sys/loginAction.action?usernamezs&password123 5.安裝nginx 前后端部署&#xff1…

qsort函數的模擬實現(冒泡排序模擬)

冒泡排序&#xff1a; 從第一個元素開始&#xff0c;依次比較相鄰的兩個元素&#xff0c;如果順序不對就交換它們。 經過一輪遍歷后&#xff0c;最大&#xff08;或最小&#xff09;的元素會排在最后。 重復進行上述步驟&#xff0c;直到沒有任何元素需要交換&#xff0c;即…

Linux了解

簡介 Linux是一種自由和開放源代碼的類UNIX操作系統&#xff0c;由芬蘭的Linus Torvalds于1991年首次發布。Linux最初是作為支持英特爾x86架構的個人電腦的一個自由操作系統&#xff0c;現在已經被移植到更多的計算機硬件平臺&#xff0c;如手機、平板電腦、路由器、視頻游戲控…

爬蟲入門到精通_實戰篇8(分析Ajax請求并抓取今日頭條美食美圖)_界面上抓取Ajax方式

1 目標 目標&#xff1a; 抓取今日頭條美食美圖&#xff0c;如下&#xff1a; 一些網頁直接請求得到的HTML代碼并沒有在網頁中看到的內容&#xff0c;因為一些信息是通過Ajax加載&#xff0c;并通過js渲染生成的&#xff0c;這時就需要通過分析網頁的請求來獲取想要爬取的內容…

解決conda環境下import TensorFlow失敗的問題

問題描述 安裝了anaconda的電腦&#xff0c;新建了一個名叫deeplearning的環境&#xff0c;在該環境下已經成功安裝了tensorflow。 于是在終端打開python并執行代碼 import tensorflow as tf print(1)除了提示 2024-02-27 21:50:00.801427: I external/local_tsl/tsl/cuda/c…

CSS 盒子模型(box model)

概念 所有HTML元素可以看作盒子&#xff0c;在CSS中&#xff0c;"box model"這一術語是用來設計和布局時使用CSS盒模型本質上是一個盒子&#xff0c;封裝周圍的HTML元素&#xff0c;它包括&#xff1a;外邊距(margin)&#xff0c;邊框(border)&#xff0c;內邊距(pad…

關于 HTTP 協議,你了解多少

HTTP協議 FastAPI 是建立在 HTTP 協議之上&#xff0c;所以為了更好的掌握 FastAPI。我們需要先簡單的了解一下 HTTP協議 簡介 HTTP&#xff08;Hypertext Transfer Protocol&#xff09;遵循經典的客戶端-服務器模型&#xff0c;客戶端打開連接以發出請求&#xff0c;然后等…

【Go語言】Go語言中的流程控制

Go語言中的流程控制 流程控制主要用于設定計算執行的順序&#xff0c;簡歷程序的邏輯結果&#xff0c;Go語言的流程控制語句與其他語言類似&#xff0c;支持如下幾種流程控制語句&#xff1a; 條件語句&#xff1a;用于條件判斷&#xff0c;對應的關鍵字有if、else和else if&a…

SQL 語句的執行順序

數據庫引擎在執行SQL語句并不是從SELECT開始執行&#xff0c;而是從FROM開始&#xff0c;執行順序如下(關鍵字前面的數字代表SQL執行的順序步驟)&#xff1a; ⑧SELECT ⑨DISTINCT ⑩①【Top Num】 【select list】 ①FROM {left_table_name} ③【join_type】 JOIN {righ…