一、Golang 接口
Golang 中接口定義了對象的行為規范,只定義規范不實現。接口中定義的規范由具體的對象來實現。
package main
import (
"fmt"
)
//接口是一個規范
type Usber interface { // 最好以 er 結尾表示接口
start()
stop()
}
// 如果接口里有方法的話,必須要通過結構體或者通過自定義類型實現這個接口。
type Phone struct {
Name string
}
// 手機要實現 usb 接口的話必須得實現 usb 接口中的所有方法
func (p Phone) start() {
fmt.Println(p.Name, "啟動")
}
func (p Phone) stop() {
fmt.Println(p.Name, "關機")
}
func main() {
p := Phone{
Name: "華為手機",
}
p.start()
var p1 Usber // Golang 中接口就是一個數據類型
p1 = p // 表示手機實現 Usb 接口
p1.start()
p1.stop()
}
輸出:
華為手機 啟動
華為手機 啟動
華為手機 關機
空接口
空接口表示沒有任何約束,因此任何類型變量都可以實現空接口。
package main
import (
"fmt"
)
// Golang 中空接口也可以直接當作類型來使用,可以表示任意類型
func main() {
var a interface{} // 空接口可以接收任意類型
a = 20
fmt.Printf("值: %v 類型:%T\n", a, a)
a = "你好golang"
fmt.Printf("值: %v 類型:%T\n", a, a)
a = true
fmt.Printf("值: %v 類型:%T\n", a, a)
}
輸出:
值: 20 類型:int
值: 你好golang 類型:string
值: true 類型:bool
1. 空接口可以作為函數的參數
package main
import (
"fmt"
)
// 1、空接口可以作為函數的參數
func show(a interface{}) {
fmt.Printf("值:%v 類型:%T\n", a, a)
}
// Golang 中空接口也可以直接當作類型來使用,可以表示任意類型
func main() {
show(20)
show("你好golang")
slice := []int{1, 2, 3, 4}
show(slice)
}
輸出:
值:20 類型:int
值:你好golang 類型:string
值:[1 2 3 4] 類型:[]int
2. map 的值實現空接口
package main
import (
"fmt"
)
// 2、map 的值實現空接口
func show(a interface{}) {
fmt.Printf("值:%v 類型:%T\n", a, a)
}
func main() {
var m1 = make(map[string]interface{})
m1["username"] = "張三"
m1["age"] = 20
m1["married"] = true
fmt.Println(m1)
var s1 = []interface{}{1, 2, "你好", true}
fmt.Println(s1)
}
輸出:
map[age:20 married:true username:張三]
[1 2 你好 true]
類型斷言
package main
import (
"fmt"
)
func main() {
var a interface{}
a = "你好golang"
v, ok := a.(string)
if ok {
fmt.Println("a就是一個string類型,值是:", v)
} else {
fmt.Println("斷言失敗")
}
}
輸出:
a就是一個string類型,值是: 你好golang
另一種寫法:
package main
import (
"fmt"
)
// 1、X.(T) 括號里表示 X 可能是的類型
func MyPrint1(x interface{}) {
if _, ok := x.(string); ok {
fmt.Println("string類型")
} else if _, ok := x.(int); ok {
fmt.Println("int類型")
} else if _, ok := x.(bool); ok {
fmt.Println("bool類型")
}
}
// 2、類型.(type)只能結合 switch 語句使用
func MyPrint2(x interface{}) {
switch x.(type) {
case int:
fmt.Println("int類型")
case string:
fmt.Println("string類型")
case bool:
fmt.Println("bool類型")
default:
fmt.Println("傳入錯誤...")
}
}
func main() {
MyPrint1("你好golang")
MyPrint1(true)
MyPrint1(20)
MyPrint2(true)
MyPrint2(20)
MyPrint2("你好golang")
}
輸出:
string類型
bool類型
int類型
bool類型
int類型
string類型
二、結構體值接收者實現接口
值接收者:如果結構體中的方法是值接收者,那么實例化后的結構體值類型和結構體指針類型都可以賦值給接口類型變量。
package main
import (
"fmt"
)
// 接口是一個規范
type Usber interface { // 最好以 er 結尾表示接口
start()
stop()
}
// 如果接口里有方法的話,必須要通過結構體或者通過自定義類型實現這個接口。
type Phone struct {
Name string
}
// 手機要實現 usb 接口的話必須得實現 usb 接口中的所有方法
func (p Phone) start() {
fmt.Println(p.Name, "啟動")
}
func (p Phone) stop() {
fmt.Println(p.Name, "關機")
}
func main() {
// 結構體值接收者實例化后的結構體值類型和結構體指針類型都可以賦值給接口變量
var p1 = Phone{
Name: "小米手機",
}
var p2 Usber = p1 // 表示讓 Phone 實現 Usb 的接口
p2.start()
var p3 = &Phone{
Name: "蘋果手機",
}
var p4 Usber = p3
p4.start()
}
輸出:
小米手機 啟動
蘋果手機 啟動
指針類型
package main
import (
"fmt"
)
// 接口是一個規范
type Usber interface { // 最好以 er 結尾表示接口
start()
stop()
}
// 如果接口里有方法的話,必須要通過結構體或者通過自定義類型實現這個接口。
type Phone struct {
Name string
}
// 手機要實現 usb 接口的話必須得實現 usb 接口中的所有方法
func (p *Phone) start() { // 指針接收者
fmt.Println(p.Name, "啟動")
}
func (p *Phone) stop() {
fmt.Println(p.Name, "關機")
}
func main() {
/*
// 錯誤寫法
var phone1 = Phone{
Name: "小米手機",
}
var p1 Usber = phone1 // 表示讓 Phone 實現 Usb 的接口
p1.start()
*/
var phone1 = &Phone{
Name: "小米",
}
var p1 Usber = phone1
p1.start()
}
輸出:
小米 啟動
結構體值接收者和指針接收者實現接口的區別
值接收者:如果結構體中的方法是值接收者,那么實例化后結構體值類型和結構體指針類型都可以賦值給接口變量。
指針接收者:如果結構體中的方法是指針接收者,那么實例化后結構體指針類型都可以賦值給接口變量,結構體值類型沒法賦值給接口變量。
package main
import (
"fmt"
)
type Animaler interface {
SetName(string)
GetName() string
}
type Dog struct {
Name string
}
func (d *Dog) SetName(name string) {
d.Name = name
}
func (d Dog) GetName() string {
return d.Name
}
type Cat struct {
Name string
}
func (c *Cat) SetName(name string) {
c.Name = name
}
func (c Cat) GetName() string {
return c.Name
}
func main() {
// Dog 實現 Animal 的接口
d := &Dog{
Name: "小黑",
}
var d1 Animaler = d
fmt.Println(d1.GetName())
d1.SetName("小黃")
fmt.Println(d1.GetName())
// Cat 實現 Animal 的接口
c := &Cat{
Name: "小花",
}
var c1 Animaler = c
fmt.Println(c1.GetName())
}
輸出:
小黑
小黃
小花
接口嵌套
package main
import (
"fmt"
)
type Ainterface interface {
SetName(string)
}
type Binterface interface {
GetName() string
}
type Animaler interface { // 接口的嵌套
Ainterface
Binterface
}
type Dog struct {
Name string
}
func (d *Dog) SetName(name string) {
d.Name = name
}
func (d Dog) GetName() string {
return d.Name
}
func main() {
d := &Dog{
Name: "小黑",
}
var d1 Animaler = d
d1.SetName("小花")
fmt.Println(d1.GetName())
}
輸出:
小花
三、Golang 中空接口和類型斷言使用細節
package main
import (
"fmt"
)
type Address struct {
Name string
Phone int
}
// Golang中空接口和類型斷言使用細節
func main() {
var userinfo = make(map[string]interface{})
userinfo["username"] = "張三"
userinfo["age"] = 20
userinfo["hobby"] = []string{"睡覺", "吃飯"}
fmt.Println(userinfo["age"]) // 20
fmt.Println(userinfo["hobby"]) // [睡覺 吃飯]
var address = Address {
Name: "李四",
Phone: 123456,
}
fmt.Println(address.Name) // 李四
userinfo["address"] = address
fmt.Println(userinfo["address"]) // {李四 123456}
hobby2, _ := userinfo["hobby"].([]string) // 類型斷言
fmt.Println(hobby2[1]) // 吃飯
address2, _ := userinfo["address"].(Address) // 類型斷言
fmt.Println(address2.Name, address2.Phone) // 李四 123456
}
輸出:
20
[睡覺 吃飯]
李四
{李四 123456}
吃飯
李四 123456