go 的结构内嵌
注意点,有点像js
func main() {fmt.Println("hello zhangbuda...")// 这个内嵌 和 js 有点像co := container{base: base{num: 22,},str: "zhangdbau hahahahah ",}fmt.Println("co: ", co)/*在 Go 语言中,如果一个类型嵌入了另一个类型,那么嵌入类型的方法就会被自动提升到外部类型,这就意味着你可以直接在外部类型上调用嵌入类型的方法。假设 co 是一个结构体,它嵌入了 base 类型,而 base 类型有一个 describe 方法。那么你可以直接在 co 上调用 describe 方法,就像这样:co.describe()。这个调用会自动转发到 base.describe 方法。所以,co.describe() 和 co.base.describe() 的结果是一致的,因为它们实际上调用的是同一个方法。但是,如果 co 自己也定义了一个 describe 方法,那么 co.describe() 就会调用 co 的 describe 方法,而不是 base.describe 方法。这是因为 Go 语言会优先调用最近的方法,而不是最匹配的方法。*/fmt.Println("co.describe: ", co.describe())fmt.Println("co.base.describe: ", co.base.describe())fmt.Println("co.base.num", co.base.num)fmt.Println("co.str: ", co.str)
}type base struct {num int
}func (b base) describe() string {// %v 格式化字符串// %v 会根据值的类型输出对应的值return fmt.Sprintf("base with num=%v", b.num)}type container struct {basestr string
}
co: {{22} zhangdbau hahahahah }
co.describe: base with num=22
co.base.describe: base with num=22
co.base.num 22
co.str: zhangdbau hahahahah
范型 是重点
package mainimport ("fmt"
)func main() {// 范型// 在 Go 语言中,如果一个类型嵌入了另一个类型,那么嵌入类型的方法就会被自动提升到外部类型,这就意味着你可以直接在外部类型上调用嵌入类型的方法。var m = map[int]string{1: "2", 2: "4", 4: "8"}fmt.Println("map: ", m)fmt.Println("keys: ", MapKeys(m))//隐式类型转换s1 := MapKeys(m)//显式类型转换s := MapKeys[string, string](map[string]string{"11": "111", "22": "222", "33": "333"})s2 := MapKeys[int, string](m)fmt.Println("s1: ", s1, "\ns: ", s, "\ns2: ", s2)lst := List[int]{}lst.push(10)lst.push(13)lst.push(23)fmt.Println("list: GetAll:", lst.GetAll())
}/*K comparable 表示 K 必须是一个可比较的类型。这是因为在 Go 语言中,map 的键必须是可比较的。这样,Go 语言才能正确地查找和比较 map 中的键
*/
func MapKeys[K comparable, V any](m map[K]V) []K {r := make([]K, 0, len(m))for k := range m {r = append(r, k)}return r
}// 范型 链表元素
type element[T any] struct {next *element[T]val T
}// 链表结构 包含 头和尾
type List[T any] struct {head, tail *element[T]
}func (lst *List[T]) push(v T) {if lst.tail == nil {//最开始初始化 链表 头部和尾部都为空lst.head = &element[T]{val: v}lst.tail = lst.head} else {// 当链表不为空时,便开始把所有元素一次插入尾部,并更新尾部lst.tail.next = &element[T]{val: v}lst.tail = lst.tail.next}
}func (lst *List[T]) GetAll() []T {// 定义一个空的切片var elemes []Tfor e := lst.head; e != nil; e = e.next {elemes = append(elemes, e.val)}return elemes
}/*再次补充 切片知识在 Go 语言中,切片(Slice)是对数组的抽象。Go 数组的长度不可改变,在特定的场景中这样的集合就不太适用。Go 中提供了一种灵活,功能强大的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。切片是一种方便、灵活且强大的包装器,使得对数组操作更加方便。例如: var number []intvar str []string
*/
map: map[1:2 2:4 4:8]
keys: [1 2 4]
s1: [1 2 4]
s: [11 22 33]
s2: [1 2 4]
list: GetAll: [10 13 23]
package mainimport ("fmt""time"
)func f(from string) {for i := 0; i < 3; i++ {fmt.Println(from, ":", i)}
}func main() {f("direct-->")go f("goroutine-->start")go func(msg string) {fmt.Println(msg)}("going--->")time.Sleep(time.Second)fmt.Println("done--->end")
}
# 运行结果
direct--> : 0
direct--> : 1
direct--> : 2
going--->
goroutine-->start : 0
goroutine-->start : 1
goroutine-->start : 2
done--->end