返回泛型类型的默认值

问题描述 投票:0回答:3

如何返回泛型类型

nil
T

func (list *mylist[T]) pop() T {
    if list.first != nil {
        data := list.first.data
        list.first = list.first.next
        return data
    }
    return nil
}

func (list *mylist[T]) getfirst() T {
    if list.first != nil {
        return list.first.data
    }
    return nil
}

我收到以下编译错误:

 cannot use nil as T value in return statement
go generics null
3个回答
98
投票

您无法为

any
类型返回 nil。例如,如果
int
用作
T
的类型参数,则返回
nil
没有任何意义。
nil
也不是结构的有效值。

您可以做的——也是有意义的——是为用于 T 的类型参数返回

零值
。例如,指针、切片的零值是
nil
,整数和浮点数的
string
0
是空字符串。

如何返回零值?只需声明一个类型为

T
的变量,然后返回它:

func getZero[T any]() T {
    var result T
    return result
}

测试:

i := getZero[int]()
fmt.Printf("%T %v\n", i, i)

s := getZero[string]()
fmt.Printf("%T %q\n", s, s)

p := getZero[image.Point]()
fmt.Printf("%T %v\n", p, p)

f := getZero[*float64]()
fmt.Printf("%T %v\n", f, f)

哪个输出(在Go Playground上尝试一下):

int 0
string ""
image.Point (0,0)
*float64 <nil>

86
投票

*new(T)
成语

这已被建议作为 golang-nuts 中的首选选项。如果/当某些零值内置函数添加到语言中时,它可能可读性较差,但更容易查找和替换。

它还允许单行分配。

new
内置为任何类型的变量分配存储空间并返回指向它的指针,因此取消引用
*new(T)
实际上会产生
T
的零值。您可以使用类型参数作为参数:

func Zero[T any]() T {
    return *new(T)
}

如果

T
具有可比性,这可以方便地检查某个变量是否为零值:

func IsZero[T comparable](v T) bool {
    return v == *new(T)
}

var
类型为
T

简单易读,但总是需要多一行:

func Zero[T any]() T {
    var zero T
    return zero
}

命名返回类型

如果您不想显式声明变量,可以使用命名返回。并不是每个人都喜欢这种语法,尽管当您的函数体比这个人为的示例更复杂时,或者如果您需要操作

defer
语句中的值时,这可能会派上用场:

func Zero[T any]() (ret T) {
    return
}

func main() {
    fmt.Println(Zero[int]())               // 0
    fmt.Println(Zero[map[string]int]())    // map[]  
    fmt.Println(Zero[chan chan uint64]())  // <nil>
}

命名返回的语法不可能与 var 声明的语法非常相似。

用你的例子:

func (list *mylist[T]) pop() (data T) {
    if list.first != nil {
        data = list.first.data
        list.first = list.first.next
    }
    return
}

对于不可空类型返回
nil

如果您确实想这样做,如问题中所述,您可以明确地返回

*T

当类型参数

T

被限制为
排除指针类型时,可以完成此操作。在这种情况下,您可以将返回类型声明为 *T
,现在您可以返回 
nil
,这是指针类型的零值。

// constraint includes only non-pointer types func getNilFor[T constraints.Integer]() *T { return nil } func main() { fmt.Println(reflect.TypeOf(getNilFor[int]())) // *int fmt.Println(reflect.TypeOf(getNilFor[uint64]())) // *uint64 }
让我再说一遍:当 

T

 
NOT 限制为任何允许指针类型的东西时,效果最好,否则你得到的是指针到指针类型:

// pay attention to this func zero[T any]() *T { return nil } func main() { fmt.Println(reflect.TypeOf(zero[int]())) // *int, good fmt.Println(reflect.TypeOf(zero[*int]())) // **int, maybe not what you want... }
    

2
投票
您可以初始化一个空变量。

if l == 0 { var empty T return empty, errors.New("empty Stack") }
    
© www.soinside.com 2019 - 2024. All rights reserved.