接口
go
package main
import "fmt"
/*
type 接口名称 interface{
方法1(参数) 返回值
方法2(参数) 返回值
}
*/
// 定义接口
type Animal interface {
eat()
}
type Dog struct {
name string
}
// Dog 实现 Animal 接口
func (d Dog) eat() {
fmt.Println("小狗爱吃骨头") // 输出内容:小狗爱吃骨头
}
type Cat struct {
name string
}
func (c Cat) eat() {
fmt.Println("小猫爱吃鱼")
}
func main() {
var d Dog
// 普通的给struct添加方法
d.eat() // 输出:小狗爱吃骨头
var a Animal
a = d
a.eat() // 输出:小狗爱吃骨头
}
// 最终程序运行输出:
// 小狗爱吃骨头
// 小狗爱吃骨头
空接口
go
// 空接口,可以存任意类型的数据
package main
import "fmt"
type A interface{}
func main() {
var a A
var a1 interface{}
a = "Hello world"
a1 = "Hello world"
fmt.Println(a, a1)
a = 20
a1 = 20
fmt.Println(a, a1)
}
空接口在map和slice的应用
css
package main
import "fmt"
func main(){
// map类型,值可以是任意类型
var a = map[string]interface{}{}
a["name"] = "张三"
a["age"] = 18
a["isGender"] = false
fmt.Println(a)
var b = []interface{}{}
b = append(b, 100)
b = append(b, "hello world")
b = append(b, false)
fmt.Println(b)
}
值和指针
go
// 值类型和指针类型
package main
import "fmt"
type Animal interface {
Eat()
}
type Dog struct {
name string
}
// ✅ 值接收者:传的是【拷贝】,方法内修改不会影响原变量
func (d Dog) Eat() {
d.name += "_rename"
fmt.Printf("%v狗吃骨头\n", d.name)
}
type Cat struct {
name string
}
// ✅ 指针接收者:传的是【地址/引用】,修改会直接改原变量
func (c *Cat) Eat() {
c.name += "_rename"
fmt.Printf("%v猫吃鱼\n", c.name)
}
func main() {
// ========== Dog:值接收者(拷贝) ==========
var d Dog
d.name = "旺财"
var d1 = &Dog{"旺财1"}
d.Eat() // 输出:旺财_rename狗吃骨头
d.Eat() // 输出:旺财_rename狗吃骨头
// 📝 笔记:两次都是【拷贝】,原变量 name 永远是 "旺财",不会累加
d1.Eat() // 输出:旺财1_rename狗吃骨头
d1.Eat() // 输出:旺财1_rename狗吃骨头
// 📝 笔记:指针调用值接收者,依然是【拷贝】,不会修改原变量
// ========== Cat:指针接收者(引用) ==========
var c Cat
c.name = "凯特"
var c1 = &Cat{"凯特1"}
c.Eat() // 输出:凯特_rename猫吃鱼
c.Eat() // 输出:凯特_rename_rename猫吃鱼
// 📝 笔记:Go自动取地址 &c,调用指针方法
// 📝 【修改的是原变量】,所以 name 会一直累加
c1.Eat() // 输出:凯特1_rename猫吃鱼
c1.Eat() // 输出:凯特1_rename_rename猫吃鱼
// 📝 笔记:指针调用指针方法
// 📝 【修改原变量】,持续累加
}
类型断言
r
x.(T)
go
package main
import "fmt"
// ==============================
// 函数作用:接收任意类型,判断并返回类型名称
// instance interface{}:空接口,可以接收【任意类型】的值
// ==============================
func getInstanceType(instance interface{}) string {
// ==============================
// 【类型选择语法】instance.(type)
// 🔥 规则:只能用在 switch 语句中,不能单独拿出来用!
// 作用:获取 instance 内部存储的【真实类型】
// ==============================
switch instance.(type) {
case int:
fmt.Println("int")
return "int"
case string:
fmt.Println("string")
return "string"
default:
fmt.Println("Unsupport")
return "nil"
}
}
func main() {
// 调用函数,传入 int 和 string
getInstanceType(100)
getInstanceType("hello")
// ==============================
// ❌ 语法错误!
// 100 是 int 字面量,不是接口
// (type) 只能在 switch 里使用
// var res = 100.(type)
// ==============================
// ==============================
// 声明空接口变量 a
// 空接口可以存储【任意类型】的值
// ==============================
var a interface{}
a = "Hello world" // 存储 string 类型
// ==============================
// 【类型断言】语法:变量.(目标类型)
// 🔥 必须满足:左边的变量 一定是【接口类型】
// content:断言成功后得到的【真实值】
// ok:断言是否成功(bool)
// ==============================
if content, ok := a.(int); ok {
fmt.Println("int类型", content)
} else if content, ok := a.(string); ok {
fmt.Println("string类型", content)
}
// ==============================
// ❌ 错误示范!
// t1 是 int 类型(普通变量),不是接口
// 类型断言【左边必须是接口变量】
// var t1 int = 10
// if content,ok := t1.(int); ok {
// fmt.Println(content)
// }
// ==============================
// ==============================
// ✅ 正确示范!
// t2 是 interface{} 空接口变量
// 可以安全使用类型断言
// ==============================
var t2 interface{} = 20
if content, ok := t2.(int); ok {
fmt.Println(content) // 输出 20
}
}