返回泛型类型的默认值

alg*_*cus 63 generics null go

如何返回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
}

Run Code Online (Sandbox Code Playgroud)

我收到以下编译错误:

 cannot use nil as T value in return statement
Run Code Online (Sandbox Code Playgroud)

icz*_*cza 79

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

\n

您可以做的\xe2\x80\x93 以及有意义的\xe2\x80\x93 是返回用于 的类型参数的零值T。例如,零值用于nil指针、切片,它是整数和浮点数的空string字符串0

\n

如何返回零值?只需声明一个类型为 的变量T,然后返回它:

\n
func getZero[T any]() T {\n    var result T\n    return result\n}\n
Run Code Online (Sandbox Code Playgroud)\n

测试它:

\n
i := getZero[int]()\nfmt.Printf("%T %v\\n", i, i)\n\ns := getZero[string]()\nfmt.Printf("%T %q\\n", s, s)\n\np := getZero[image.Point]()\nfmt.Printf("%T %v\\n", p, p)\n\nf := getZero[*float64]()\nfmt.Printf("%T %v\\n", f, f)\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
int 0\nstring ""\nimage.Point (0,0)\n*float64 <nil>\n
Run Code Online (Sandbox Code Playgroud)\n


bla*_*een 71

成语*new(T)

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

它还允许单行分配。

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

func Zero[T any]() T {
    return *new(T)
}
Run Code Online (Sandbox Code Playgroud)

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

func IsZero[T comparable](v T) bool {
    return v == *new(T)
}
Run Code Online (Sandbox Code Playgroud)

var类型的T

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

func Zero[T any]() T {
    var zero T
    return zero
}
Run Code Online (Sandbox Code Playgroud)

命名返回类型

如果您不想显式声明变量,可以使用命名返回。并不是每个人都喜欢这种语法,尽管当您的函数体比这个人为的示例更复杂时,或者如果您需要操作语句中的值时,这可能会派上用场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>
}
Run Code Online (Sandbox Code Playgroud)

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

使用你的例子:

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

返回nil不可空类型

如果您确实想这样做,如问题中所述,您可以明确return*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
}
Run Code Online (Sandbox Code Playgroud)

让我再次声明一下:当不受T任何允许指针类型的限制时,效果最好,否则您得到的是指针到指针类型:

// 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...
}
Run Code Online (Sandbox Code Playgroud)