@
目錄
1. 介面定義
-
Interface 型別可以定義一組方法,不需要實現,並且不能包含任何的變數,稱之為介面
-
介面不需要顯示的實現,只需要一個變數,含有介面型別中的所有方法,那麼這個變數就實現了這個介面,如果一個變數含有多個interface 型別的方法,那麼這個變數就實現了多個介面
-
介面又稱為動態資料型別,在進行介面使用的的時候,會將介面對位置的動態型別改為所指向的型別
會將動態值改成所指向型別的結構體 -
每個介面由數個方法組成,介面的定義格式如下:
其中引數列表和返回值列表中的引數變數名可以省略
type 介面型別名 interface{
方法名1( 引數列表1 ) 返回值列表1
方法名2( 引數列表2 ) 返回值列表2
…
}
- 自定義介面步驟
① 定義介面
② 定義結構體
③ 介面實現(繫結結構體)
④ 定義介面變數,初始化結構體,呼叫介面實現功能
1.1 空介面
空介面就相當於一個空指標
package main
import "fmt"
//定義空介面
type Test interface{}
func main() {
//宣告介面方法1
var t Test
fmt.Printf("t的型別: %T, t的值: %v\n", t, t)
//宣告介面方法2
var a interface{}
var b int
a = b
fmt.Printf("a的型別: %T, a的值: %v\n", a, a)
}
//輸出結果如下
t的型別: <nil>, t的值: <nil>
a的型別: int, a的值: 0
1.2 實現單一介面
結構體使用介面列印資訊
package main
import "fmt"
type Student struct {
Name string
Age int
Score float32
}
//介面定義:介面是功能的抽象,不需要實現
type Test interface {
Print()
}
//指標型別實現介面
func (p *Student) Print() {
fmt.Printf("name:[%s]\n", p.Name)
fmt.Printf("age:[%d]\n", p.Age)
fmt.Printf("score:[%f]\n", p.Score)
}
//值型別實現介面
/*
func (p Student) Print() {
fmt.Printf("name:[%s]\n", p.Name)
fmt.Printf("age:[%d]\n", p.Age)
fmt.Printf("score:[%f]\n", p.Score)
}
*/
func main() {
//宣告介面變數
var t Test
//結構體初始化
var stu Student = Student{
Name: "zhangsan",
Age: 18,
Score: 90,
}
//把結構體賦值給介面
t = &stu
//介面功能
t.Print()
}
//輸出結果如下
name:[zhangsan]
name:[18]
name:[90.000000]
1.3 介面多方法實現
package main
import "fmt"
type Student struct {
Name string
Age int
Score float32
}
//介面定義:介面是功能的抽象,不需要實現
type Test interface {
Print()
Sleep()
}
//介面的實現
func (p *Student) Print() {
fmt.Printf("name:[%s]\n", p.Name)
fmt.Printf("age:[%d]\n", p.Age)
fmt.Printf("score:[%f]\n", p.Score)
}
//介面中包含多個方法,如果要使用此介面就要實現介面中包含的所有方法
func (p *Student) Sleep() {
fmt.Println("正在睡眠~")
}
func main() {
//宣告介面變數
var t Test
//結構體初始化
var stu Student = Student{
Name: "zhangsan",
Age: 18,
Score: 90,
}
//把結構體賦值給介面
t = &stu
//介面功能
t.Print()
t.Sleep()
}
//輸出結果如下
name:[zhangsan]
name:[18]
name:[90.000000]
正在睡眠~
- 示例,在電腦上定義一個USB介面,實現滑鼠、U盤、風扇的功能
package main
import "fmt"
//定義電腦
type Computer struct {
Brand string //品牌
Price float32 //價格
}
//定義USB介面
type USB interface {
mouse()
store()
fan()
}
//介面功能實現
func (c Computer) mouse() {
fmt.Println("滑鼠")
}
func (c Computer) store() {
fmt.Println("U盤")
}
func (c Computer) fan() {
fmt.Println("風扇")
}
func main() {
//初始化結構體
var com Computer
//初始化介面
var usb USB
com.Brand = "thinkpad"
com.Price = 5000
//介面呼叫
usb = com
usb.mouse()
usb.fan()
usb.store()
}
//輸出結果如下
滑鼠
風扇
U盤
2. 多型
- 對於同一個介面,賦予給不同的結構體,使用相同的方法而產生出不同的操作,稱之為多型。
2.1 為不同資料型別的實體提供統一的介面
package main
import "fmt"
//父結構體
type Persion struct {
Name string
Age int
}
//學生子結構體
type Student struct {
Persion
Score float32
}
//教師子結構體
type Teacher struct {
Persion
Class int
}
//介面定義:介面時功能的抽象,不需要實現
type Test interface {
Print()
Sleep()
}
//學生結構體的實現
func (p *Student) Print() {
fmt.Printf("name:[%s]\n", p.Name)
fmt.Printf("age:[%d]\n", p.Age)
fmt.Printf("Score:[%f]\n", p.Score)
}
//教師結構體的實現
func (p *Teacher) Print() {
fmt.Printf("name:[%s]\n", p.Name)
fmt.Printf("age:[%d]\n", p.Age)
fmt.Printf("Class:[%d]\n", p.Class)
}
//介面中包含多個方法,如果要使用此介面就要實現介面中包含的所有方法
func (p *Student) Sleep() {
fmt.Println("正在睡眠~")
}
func (p *Teacher) Sleep() {
fmt.Println("正在休息~")
}
func main() {
//宣告介面變數
var t Test
//學生初始化
var stu Student
stu.Name = "zhangsan"
stu.Age = 18
stu.Score = 90
//教師初始化
var tea Teacher
tea.Name = "lisi"
tea.Age = 25
tea.Class = 3
//學生介面功能呼叫實現
t = &stu
t.Print()
t.Sleep()
fmt.Println("----------------------------")
//教師介面功能呼叫實現
t = &tea
t.Print()
t.Sleep()
}
//輸出結果如下
name:[zhangsan]
age:[18]
Score:[90.000000]
正在睡眠~
----------------------------
name:[lisi]
age:[25]
Class:[3]
正在休息~
2.2 多介面的實現
package main
import "fmt"
//介面1
type Test1 interface {
Print()
}
//介面2
type Test2 interface {
Sleep()
}
//結構體
type Student struct {
Name string
Age int
Score float32
}
//介面1實現
func (s Student) Print() {
fmt.Printf("name:[%s]\n", s.Name)
}
//介面2實現
func (s Student) Sleep() {
fmt.Println("正在睡眠")
}
func main() {
//介面1變數
var t1 Test1
//介面2變數
var t2 Test2
//初始化結構體
var stu Student = Student{
Name: "zhangsan",
Age: 18,
Score: 90,
}
//呼叫介面實現功能
t1 = stu
t1.Print()
t2 = stu
t2.Sleep()
}
//輸出結果如下
name:[zhangsan]
正在睡眠
3. 系統介面呼叫
- 示例
使用介面進行排序
package main
import (
"fmt"
"math/rand"
"sort"
)
//結構體
type Student struct {
Name string
Age int
Score float32
}
//切片
type StudentArray []Student
//go語言提供了sort 介面。使用介面裡的方法即可
//實現sort介面
func (sa StudentArray) Len() int {
return len(sa)
} //獲取切片長度
func (sa StudentArray) Less(i, j int) bool {
return sa[i].Name > sa[j].Name
} //兩數比大小
func (sa StudentArray) Swap(i, j int) {
sa[i], sa[j] = sa[j], sa[i]
} //兩數交換
func main() {
//Student 切片
var stus StudentArray
//生成10個結構體,放入切片中
for i := 0; i < 10; i++ {
var stu Student = Student{
Name: fmt.Sprintf("stu%d", rand.Intn(100)),
Age: rand.Intn(120),
Score: rand.Float32() * 100,
}
//結構體元素存入到切片中
stus = append(stus, stu)
}
//遍歷
for _, v := range stus {
fmt.Println(v)
}
fmt.Println("--------------------------")
//排序
sort.Sort(stus)
//遍歷
for _, v := range stus {
fmt.Println(v)
}
}
4. 介面巢狀
- 示例:
檔案讀寫測試
package main
import "fmt"
//讀取的介面
type Reader interface {
Read()
}
//寫入的介面
type Writer interface {
Writer()
}
//介面的巢狀
type ReadWriter interface {
Reader
Writer
}
//檔案結構體
type File struct{}
//實現Reader介面
func (f *File) Read() {
fmt.Println("檔案讀取")
}
//實現Writer介面
func (f *File) Writer() {
fmt.Println("檔案寫入")
}
//定義讀寫操作函式
func Test(rw ReadWriter) { //rw為介面變數
rw.Read() //使用讀寫的方法
rw.Writer()
}
func main() {
var f File //定義結構體,初始化檔案
Test(&f)
}
//輸出結果如下
檔案讀取
檔案寫入
5. 型別斷言
- 作用:因為介面是一般型別,需要明確具體型別的時候就需要使用型別斷言
示例
package main
import "fmt"
func main() {
//定義空介面
var a interface{}
var b int
a = b //a為int型別
//斷言賦值
fmt.Printf("a= %v, 型別: %T\n", a, a)
c := a.(int)
fmt.Printf("c= %v, 型別: %T\n", c, c)
}
//輸出結果如下
a= 0, 型別: int
c= 0, 型別: int
5.1 斷言判斷
package main
import "fmt"
func main() {
//定義空介面
var a interface{}
var b string
a = b //a為int型別
//斷言賦值
fmt.Printf("a= %v, 型別: %T\n", a, a)
c, err := a.(int)
if err {
fmt.Printf("c= %v, 型別: %T\n", c, c)
} else {
fmt.Println("不是int型別")
}
}
//輸出結果如下
a= , 型別: string
不是int型別
package main
import "fmt"
func Test(t interface{}) {
//轉換型別判斷
v, err := t.(int)
if !err {
fmt.Println("type is not int")
return
}
v++
fmt.Println(v)
}
func main() {
a := "張三"
Test(a)
}
//輸出結果如下
type is not int
5.2 多型別判斷
package main
import "fmt"
func classifier(items ...interface{}) {
//遍歷複雜集合
for i, v := range items {
//變數.(type)職能作用在switch語句中,專門用於判斷型別
switch v.(type) {
case bool:
fmt.Printf("第 %d 個資料型別是 bool\n", i)
case int, int32, int64:
fmt.Printf("第 %d 個資料型別是 int\n", i)
case float32, float64:
fmt.Printf("第 %d 個資料型別是 float\n", i)
case string:
fmt.Printf("第 %d 個資料型別是 string\n", i)
default:
fmt.Printf("第 %d 個資料型別是其他型別\n", i)
}
}
}
func main() {
//傳入多種型別引數
classifier("張三", 3.14, true, 80, nil)
}
//輸出結果如下
第 0 個資料型別是 string
第 1 個資料型別是 float
第 2 個資料型別是 bool
第 3 個資料型別是 int
第 4 個資料型別是其他型別
6. 使用介面實現連結串列插入
package main
import "fmt"
//節點結構體
type LinkNode struct {
data interface{}
next *LinkNode
}
//連結串列結構體
type Link struct {
head *LinkNode
tail *LinkNode
}
//從頭部插入
func (p *Link) InsertHead(data interface{}) {
node := &LinkNode{
data: data,
next: nil,
}
//判斷是否為空連結串列
if p.head == nil && p.tail == nil {
p.head = node
p.tail = node
return
}
//當前節點的next是原頭部節點
node.next = p.head
//更新頭部
p.head = node
}
//從尾部插入
func (p *Link) InsertTail(data interface{}) {
node := &LinkNode{
data: data,
next: nil,
}
//判斷是否為空連結串列
if p.head == nil && p.tail == nil {
p.head = node
p.tail = node
return
}
//原尾部節點的next是當前節點
p.tail.next = node
//更新尾部
p.tail = node
}
//遍歷方法
func (p *Link) Req() {
lp := p.head
for lp != nil {
fmt.Println(lp)
lp = lp.next
}
}
func main() {
//定義連結串列
var intLink Link
for i := 0; i < 10; i++ {
//intLink.InsertHead(i)
intLink.InsertTail(i)
}
intLink.Req()
}
//輸出結果如下
&{0 0xc000096078}
&{1 0xc000096090}
&{2 0xc0000960a8}
&{3 0xc0000960c0}
&{4 0xc0000960d8}
&{5 0xc0000960f0}
&{6 0xc000096108}
&{7 0xc000096120}
&{8 0xc000096138}
&{9 <nil>}