5

我正在尝试在 Go 中编写一个使用“通用”类型计算方程的包。具体来说,我想实现runge kutta 5 近似。

此近似计算仅使用 at 的值、开始时间、步长和微分方程在该点处的(未知)函数的值,该微分方程的y形式为where is some function。t0 + hyt0t0hdgldy/dt = g(t,y)g

在使用标量类型时,这种近似的行为与使用向量(甚至矩阵)时的行为完全相同。更一般地说:它适用于可以添加/减去相同类型的值并且可以通过标量缩放的所有内容(我使用float64

所以我试图将其表达为一个 Go 接口:

type Numeric interface {
    Add(rhs Numeric) Numeric
    Sub(rhs Numeric) Numeric
    Mul(rhs float64) Numeric
}

但是当我尝试“实现”这个接口时,由于参数类型,我遇到了麻烦:

type Vec6F struct {
    x, y, z float64
    vx, vy, vz float64
}

func (lhs *Vec6F) Add(rhs *Vec6F) rk5.Numeric {
    result := new(Vec6F)
    result.x = lhs.x + rhs.x
    result.y = lhs.y + rhs.y
    result.z = lhs.z + rhs.z
    result.vx = lhs.vx + rhs.vx
    result.vy = lhs.vy + rhs.vy
    result.vz = lhs.vz + rhs.vz
    return result
}

这给了我错误

cannot use result (type *Vec6F) as type rk5.Numeric in return argument:
        *Vec6F does not implement rk5.Numeric (wrong type for Add method
                have Add(*Vec6F) rk5.Numeric
                want Add(rk5.Numeric) rk5.Numeric

也就是说,一方面对我来说绝对合乎逻辑(因为 rhs 可能是另一个实现 Numeric 的对象)

但另一方面:我如何在 Go 中表达类似的东西?在 C++ 中,我可以改用运算符重载,但这在 go 中是不可能的。

4

3 回答 3

2

为了通用,您的Add方法必须带一个Numeric参数。处理这个问题的正常方法是使用这样的类型断言(在操场上

func (lhs *Vec6F) Add(_rhs Numeric) Numeric {
    result := new(Vec6F)
    rhs := _rhs.(*Vec6F) // type assertion - will panic if wrong type passes
    result.x = lhs.x + rhs.x
    result.y = lhs.y + rhs.y
    result.z = lhs.z + rhs.z
    result.vx = lhs.vx + rhs.vx
    result.vy = lhs.vy + rhs.vy
    result.vz = lhs.vz + rhs.vz
    return result
}

如果您想要在不同类型之间进行转换,您也可以使用类型开关。

于 2013-01-21T07:51:25.470 回答
1

事实上,go 中不支持泛型。如果你想让一个类型实现一个接口,方法的原型需要完全匹配:你需要func (lhs *Vec6F) Add(rhs Numeric) Numeric.

这是使用类型断言编写此方法的尝试:

func (lhs *Vec6F) Add(rhs Numeric) Numeric {
    vrhs := rhs.(*Vec6F)
    result := new(Vec6F)
    result.x = lhs.x + vrhs.x
    result.y = lhs.y + vrhs.y
    result.z = lhs.z + vrhs.z
    result.vx = lhs.vx + vrhs.vx
    result.vy = lhs.vy + vrhs.vy
    result.vz = lhs.vz + vrhs.vz
    return result
}

它可以编译并且在使用正确类型的参数调用时应该可以工作,但是,我会说这是一种滥用。

没有什么能阻止您(除了运行时错误)使用此方法将向量添加到标量,因为它们都将实现Numeric. 最后,您不会从使用接口抽象中获得任何收益。

在这种情况下,go 哲学将决定使用特定于类型的方法/函数。

于 2013-01-21T07:49:38.647 回答
0

您遇到了两个问题。

1.) 它没有编译,并抱怨接口不匹配的原因是因为 Vec6F 不满足 rk5.Numeric 的函数签名。返回值和输入参数都必须匹配类型。

http://play.golang.org/p/kc9V9EXxJq解决了这个问题,但创建了一个新问题......

2.) 为了使方法签名匹配,以便 Vec6F 满足 Numeric 的签名,它破坏了对属性值执行数字操作的能力。这是因为接口只有方法,没有属性。

在您的用例中,Numeric 接口提供一个访问器方法是否有意义,该方法将返回一个矩阵数组,然后接收器将执行 Add|Sub|Multi ?这可能会使每个接口实现的方法中需要做的事情变得复杂,但我认为这会让你得到你想要的。

于 2013-01-21T07:50:58.547 回答