更多的结构体
在Golang中,数组的长度是不能改变的,为了更灵活地适配更多需求,Golang设计了一种名为Slice的数据结构,用于实现对动态数组的抽象:
complex_2 := Complex{1, 3}
complex_3 := Complex{1, 4}
complex_list := [2]Complex{complex_2, complex_3}
complex_slice := []Complex{complex_2, complex_3}接口
我很久之前就听说过Golang有接口,当时还很意外——一个非OOP的语言,为什么会有接口?稍微学习了一点,写出了一点代码:
package main
import (
"fmt"
)
type Lamp interface {
On() string
Off() string
GetStatus() bool
}
type TableLamp struct {
IsOn bool
Information string
}
func (tablelamp *TableLamp) On() string {
tablelamp.IsOn = true
return tablelamp.Information + " ON"
}
func (tableLamp *TableLamp) Off() string {
tableLamp.IsOn = false
return tableLamp.Information + " OFF"
}
func (tableLamp TableLamp) GetStatus() bool {
return tableLamp.IsOn
}
func main() {
tableLamp := TableLamp{
Information: "Table Lamp Switches",
IsOn: false,
}
fmt.Println(tableLamp.On())
fmt.Println(tableLamp.GetStatus())
fmt.Println(tableLamp.Off())
fmt.Println(tableLamp.GetStatus())
}Golang的所谓接口,在我看来就是模仿OOP的设计,其含义为规定了一类范畴的结构体,必须要实现的方法。
不过,很有意思的是,Golang引入了一个很神奇的东西——空接口,这个东西可以承载任意类型的参数:
func main() {
var i interface{}
i = 1
fmt.Println(i)
i = "This is a string"
fmt.Println(i)
}对我来说,空接口干的事其实是实现了一个类型声明——any。在Golang1.18版本中,也的确引入了这个关键字,官方解释是,any和空接口是一样的,所以这两种写法是一样的:
func main() {
var i any
i = 1
fmt.Println(i)
i = "This is a string"
fmt.Println(i)
}泛型
泛型是我认为最有趣的一个功能,一个代码实例如下:
package main
import (
"fmt"
)
type EnableString interface {
ToString() string
}
type BasicString struct {
str string
}
func (bs BasicString) ToString() string {
return bs.str
}
func CompareStringLength[T EnableString](a, b T) bool {
return len(a.ToString()) > len(b.ToString())
}
func main() {
bs1 := BasicString{str: "Hello"}
bs2 := BasicString{str: "Exactly"}
fmt.Println(CompareStringLength(bs1, bs2))
}Golang中的泛型是极其灵活的,可以通过实现一个接口自定义泛型的约束,只要一个结构体实现了这个约束,就可以应用泛型函数进行处理。通过泛型我们可以实现很多有趣的功能,比如去重功能:
func FindDuplicatedElement[T comparable](a []T) []T {
result := []T{}
for index, element := range a {
for _, element2 := range a[index+1:] {
if element == element2 {
result = append(result, element)
}
}
}
return result
}学习到这里,我已经很喜欢Golang这门语言了。
并发
众所周知,b站的一部分开发是依靠Golang完成的,那么我先入为主地认为,Golang的在处理并发场景下也是不错的。在Golang里,创建一个新的线程其实非常简单,一个代码的例子如下:
package main
import (
"fmt"
"time"
)
func task1() {
for i := 0; i < 3; i++ {
fmt.Println("This is task1 executing...")
}
time.Sleep(100 * time.Millisecond)
}
func task2() {
for i := 0; i < 3; i++ {
fmt.Println("This is task2 executing...")
}
time.Sleep(100 * time.Millisecond)
}
func main() {
go task1()
go task2()
for i := 0; i < 3; i++ {
fmt.Println("This is main executing...")
time.Sleep(100 * time.Millisecond)
}
}只需要go关键字,就可以创建一个运行某个函数的新线程。至于通道等机制,我打算通过写实际的项目再来学习。
继承
Golang虽然不是一个OOP语言,但是也在一定程度上实现了继承的功能,只不过,和OOP语言相比,Golang的继承更像是一个包含关系,而非严格意义上的派生关系,比如一个来自菜鸟教程的例子:
package main
import "fmt"
// 定义接口
type Speaker interface {
Speak()
}
// 父结构体
type Animal struct {
Name string
}
// 实现接口方法
func (a *Animal) Speak() {
fmt.Println(a.Name, "says hello!")
}
// 子结构体
type Dog struct {
Animal
Breed string
}
func main() {
var speaker Speaker
dog := Dog{
Animal: Animal{Name: "Buddy"},
Breed: "Golden Retriever",
}
speaker = &dog
speaker.Speak() // 通过接口调用方法
}子结构体通过包含父结构体,实现了所谓的继承操作,除此之外,方法的继承也是在这个包含关系基础上的。
总结
通过加起来一天的上手,Golang具体是怎么一门语言已经十分清晰了,下一步我打算用Golang重写之前用C或者Java等语言实现的一些玩具项目,进一步熟悉Golang本身。
目前为止,我非常喜欢Golang这门语言,因为我所接触的场景大多不是性能优先的场景,所以不需要极致的高性能。Golang或许是我的最佳选择。