当使用嵌入式结构时,Gonum会引发错误的区域恐慌

时间:2018-08-21 14:22:20

标签: go struct gonum

我正在使用gonum执行一些线性代数计算。扩展了原始的mat.VecDense结构之后,在对自身应用方法时,我遇到了“错误区域:相同”的恐慌。当我使用gonum提供的原始安装程序时,不会发生此错误。

这是我的实现方式:

type Vector struct {
    mat.VecDense
}
func NewVector(n int, data []float64) *Vector {
    return &Vector{*mat.NewVecDense(n, data)}
}

我正在使用以下代码段对其进行测试:

func main() {
    u, v := mat.NewVecDense(3, []float64{1, 2, 3}), mat.NewVecDense(3, []float64{4, 5, 6})
    fmt.Printf("[U - NewVecDense]\tADDRESS: %v, VALUE: %v\n", &u, u)
    fmt.Printf("[V - NewVecDense]\tADDRESS: %v, VALUE: %v\n", &v, v)
    u.AddVec(u, v)

    fmt.Println("-------------------------")
    x, y := NewVector(3, []float64{1, 2, 3}), NewVector(3, []float64{4, 5, 6})
    fmt.Printf("[X - NewVector]\tADDRESS: %v, VALUE: %v\n", &x, x)
    fmt.Printf("[Y - NewVector]\tADDRESS: %v, VALUE: %v\n", &y, y)
    x.AddVec(x, y)
    fmt.Println(x)
}

第一个加法执​​行得很好,而第二个加法失败:

[U - NewVecDense]   ADDRESS: 0xc42000c028, VALUE: &{{[1 2 3] 1} 3}
[V - NewVecDense]   ADDRESS: 0xc42000c030, VALUE: &{{[4 5 6] 1} 3}
-------------------------
[X - NewVector] ADDRESS: 0xc42000c040, VALUE: &{{{[1 2 3] 1} 3}}
[Y - NewVector] ADDRESS: 0xc42000c048, VALUE: &{{{[4 5 6] 1} 3}}
panic: mat: bad region: identical

AddVec是方法implemented by gonum

func (v *VecDense) AddVec(a, b Vector)

为什么会发生这种情况,请问实现此目的的正确方法是什么?


编辑:

感谢@Himanshu,我设法解决了这个问题。

我为正在使用的每个方法创建了传递方法,将结构的正确级别传递给了:

type Vector struct {
    *mat.VecDense
}

func NewVector(n int, data []float64) Vector {
    return Vector{mat.NewVecDense(n, data)}
}

func (v *Vector) AddVec(a, b Vector) {
    v.VecDense.AddVec(a.VecDense, b.VecDense)
}

func (v *Vector) SubVec(a, b Vector) {
    v.VecDense.SubVec(a.VecDense, b.VecDense)
}

func (v *Vector) ScaleVec(alpha float64, a Vector) {
    v.VecDense.ScaleVec(alpha, a.VecDense)
}

func (v *Vector) AddScaledVec(a Vector, alpha float64, b Vector) {
    v.VecDense.AddScaledVec(a.VecDense, alpha, b.VecDense)
}

此外-我不确定这是否是正确的方法-我也将NewVector的返回类型从指针更改为值,因为它仍然持有指向mat.VecDense的指针。请注意,*mat.VecDense满足了gonum的Vector接口,因此,如上面的示例所示,将此内部字段传递给方法可以正常工作。

2 个答案:

答案 0 :(得分:0)

在Golang中,对升级方法的描述为

  

升级字段的作用类似于结构的普通字段,除了它们   不能用作结构的复合文字中的字段名称。

给定一个结构类型S和一个定义的类型T,在该方法的方法集中包括了以下改进的方法:

  • 如果S包含嵌入字段T,则S和* S的方法集都包括接收者T的提升方法。* S的方法集也包括接收者* T的提升方法。
  • 如果S包含一个嵌入字段* T,则S和* S的方法集都包括接收者T或* T的提升方法。

问题是您要将指针类型参数传递给AddVec函数。但是您在第二种情况下使用的是指针类型字段。

func (v *VecDense) AddVec(a, b Vector)

要注意的另一件事是AddVec的值类型参数为Vector结构,但是您将指针传递给Vector字段,

x, y := NewVector(3, []float64{1, 2, 3}), NewVector(3, []float64{4, 5, 6}) 

以上代码x,y中的指针类型是从NewVector返回的

x.AddVec(x, y)

答案 1 :(得分:0)

问题是进行阴影检测时会比较指针。这是IMO的错误。我刚刚提交了https://github.com/gonum/gonum/issues/945