Skip to content

Daily Study

更新: 5/26/2025 字数: 0 字 时长: 0 分钟

Daily Plan

#todo

  • [ ]

Go的类型断言

语法:value, ok := x.(T) or value := x.(T) x 是一个接口类型的变量,T 是一个具体的类型,如果断言成功,value返回 x 转化为T类型的值。

具体使用场景:

  • 处理异构集合,使用 type switch 结构,代码如下:
go
package main

import "fmt"

func main() {
    items := []interface{}{10, "hello", true, 3.14, []int{1, 2, 3}}

    for _, item := range items {
        switch v := item.(type) { // type switch
        case int:
            fmt.Printf("Item is an int: %d\n", v)
        case string:
            fmt.Printf("Item is a string: %s\n", v)
        case bool:
            fmt.Printf("Item is a bool: %t\n", v)
        default:
            fmt.Printf("Item is of an unknown type: %T\n", v)
        }
    }
}
  • io.Reader/Write/ReaderWrite 等类型,检查接口是否实现了另一个更具体的接口
  • 自定义错误类型并检查,主要是在错误处理时通过类型断言来检查错误的具体类型,然后做更细致的处理。

何时避免或谨慎使用类型断言:

  • 过度使用类型断言可能表明设计问题:如果你的代码中充斥着类型断言,可能意味着你没有充分利用接口的抽象能力。尝试通过定义更合适的接口方法来避免直接访问具体类型。
  • 优先使用接口方法:如果可以通过接口定义的方法来完成操作,那么就不应该使用类型断言去获取具体类型再调用其方法。
  • 警惕单返回值断言:如前所述,单返回值形式的类型断言在失败时会引发 panic,这可能导致程序崩溃。除非你绝对确定类型,否则总是使用双返回值形式并检查 ok 的值。

Go的泛型

参照链接:后端 - Go 1.18 泛型全面讲解:一篇讲清泛型的全部 - 个人文章 - SegmentFault 思否

泛型的作用:

  • 代码复用:编写一次,用于多种类型。例如,一个通用的切片操作函数(如查找、过滤)或数据结构(如链表、树)。
  • 类型安全:与使用 interface{} (或 any) 然后进行类型断言相比,泛型在编译时就能提供类型检查,从而提高了代码的健壮性。
  • 性能:通常情况下,泛型代码可以像特定类型的代码一样高效,避免了类型断言可能带来的运行时开销。

Go的泛型(或者或类型形参)目前可使用在3个地方:

  • 泛型类型,类型定义中带类型形参的类型:type Slice[T int|float32|float64 ] []T
  • 泛型receiver,泛型类型的receiver
go
type MySlice[T int | float32] []T

func (s MySlice[T]) Sum() T {
    var sum T
    for _, value := range s {
        sum += value
    }
    return sum
}
  • 泛型函数 - 带类型形参的函数
go
func Add[T int | float32 | float64](a T, b T) T {
    return a + b
}

一些概念:

  1. 类型形参
  2. 类型形参列表
  3. 类型实参
  4. 类型约束
  5. 实例化 - 泛型在使用前一定要进行实例化,传入类型实参后才能够调用

泛型无法使用匿名结构体,导致在做单元测试的时候会非常麻烦,例如:

go
testCase := struct {
        caseName string
        got      int
        want     int
    }{
        caseName: "test OK",
        got:      100,
        want:     100,
    }
//错误    
testCase := struct[T int|string] {
        caseName string
        got      T
        want     T
    }[int]{
        caseName: "test OK",
        got:      100,
        want:     100,
    }

泛型接口

接口的两种类型:

  • 基本接口:接口定义中如果只有方法
  • 一般接口:接口内不光只有方法,还有类型

空接口和any:

  1. 空接口 interface{}虽然空接口内没有写入任何的类型,但它代表的是所有类型的集合,而非一个 空集
  2. 类型约束中指定 空接口 的意思是指定了一个包含所有类型的类型集,并不是类型约束限定了只能使用 空接口 来做类型形参
  3. any 实际上就是 interaface{} 的别名(alias),两者完全等价

菜就多练

本站访客数 人次 本站总访问量