You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用接口指针作为泛型参数时触发空指针解引用panic问题求助

问题:泛型接口指针接收者引发nil指针解引用Panic

问题重现

定义泛型Storage接口及指针接收者实现的Base结构体:

type Storage[T any] interface {
    Allocate(size int)
}

type Base[T any] struct {
    data []T
}

func (b *Base[T]) Allocate(size int) {
    b.data = make([]T, size)
}

尝试用该接口约束Tensor泛型参数并初始化时触发panic:

type Tensor[T any, U Storage[T]] struct {
    data U
}

func NewTensor[T any, U Storage[T]](size int) *Tensor[T, U] {
    result := &Tensor[T, U]{}
    result.data = *new(U)
    result.data.Allocate(size)
    return result
}

func main() {
    t := NewTensor[float32, *Base[float32]](10)
    fmt.Println(t)
}

Panic信息:

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x1 addr=0x8 pc=0x47de63]

goroutine 1 [running]:
main.(*Base[...]).Allocate(...)
        .../goten/debug/debug.go:14
main.NewTensor[...](0x60)
        .../goten/debug/debug.go:24 +0x47
main.main()
        .../goten/debug/debug.go:29 +0x25
exit status 2

问题原因

当U为*Base[float32]时,new(U)返回的是**Base[float32]类型指针,解引用*new(U)得到的是nil(指针类型零值为nil)。此时调用result.data.Allocate(size)本质是对nil指针调用方法,触发nil指针解引用panic。

解决方案

方案1:反射初始化兼容指针/值类型

利用反射创建U的有效实例,无需修改现有接口,兼容所有Storage实现:

import "reflect"

func NewTensor[T any, U Storage[T]](size int) *Tensor[T, U] {
    result := &Tensor[T, U]{}
    uType := reflect.TypeOf((*U)(nil)).Elem()
    var u U
    
    if uType.Kind() == reflect.Ptr {
        // 创建指针类型的非nil实例
        u = reflect.New(uType.Elem()).Interface().(U)
    } else {
        // 值类型直接零值初始化
        u = reflect.Zero(uType).Interface().(U)
    }
    
    result.data = u
    result.data.Allocate(size)
    return result
}

方案2:添加构造约束

给Storage相关类型添加构造方法,通过约束保证可初始化:

type Storage[T any] interface {
    Allocate(size int)
}

// 定义构造约束
type StorageConstructor[T any, U Storage[T]] interface {
    New() U
}

// 给Base指针类型实现构造方法
func (*Base[T]) New() *Base[T] {
    return &Base[T]{}
}

type Tensor[T any, U Storage[T]] struct {
    data U
}

func NewTensor[T any, U Storage[T], C StorageConstructor[T, U]](size int) *Tensor[T, U] {
    result := &Tensor[T, U]{}
    var c C
    result.data = c.New()
    result.data.Allocate(size)
    return result
}

// 调用时传入构造类型
func main() {
    t := NewTensor[float32, *Base[float32], *Base[float32]](10)
    fmt.Println(t)
}

最终可行代码示例

采用反射方案的完整可运行代码:

package main

import (
    "fmt"
    "reflect"
)

type Storage[T any] interface {
    Allocate(size int)
}

type Base[T any] struct {
    data []T
}

func (b *Base[T]) Allocate(size int) {
    b.data = make([]T, size)
}

type Tensor[T any, U Storage[T]] struct {
    data U
}

func NewTensor[T any, U Storage[T]](size int) *Tensor[T, U] {
    result := &Tensor[T, U]{}
    uType := reflect.TypeOf((*U)(nil)).Elem()
    var u U
    
    if uType.Kind() == reflect.Ptr {
        u = reflect.New(uType.Elem()).Interface().(U)
    } else {
        u = reflect.Zero(uType).Interface().(U)
    }
    
    result.data = u
    result.data.Allocate(size)
    return result
}

func main() {
    t := NewTensor[float32, *Base[float32]](10)
    fmt.Printf("Tensor data length: %d\n", len(t.data.data))
}

运行输出:

Tensor data length: 10

内容的提问来源于stack exchange,提问作者user3483203

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 02:40:27