Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Generics Go(语言)通用数字类型/接口_Generics_Interface_Go - Fatal编程技术网

Generics Go(语言)通用数字类型/接口

Generics Go(语言)通用数字类型/接口,generics,interface,go,Generics,Interface,Go,我正在尝试用Go编写一个包,它使用“泛型”类型计算一个等式。具体来说,我想实现runge-kutta 5近似 该近似仅使用t0处y的值、开始时间t0、步长h和形式为dy/dt=g(t,y)的微分方程dgl计算点t0+h处(未知)函数y的值其中g是一些函数 使用标量类型时,此近似的行为与使用向量(甚至矩阵)时完全相同。更一般地说:它适用于可以添加/减去相同类型的值的所有内容,并且可以通过标量进行缩放(对于标量,我使用float64) 因此,我尝试将其表示为Go接口: type Numeric in

我正在尝试用Go编写一个包,它使用“泛型”类型计算一个等式。具体来说,我想实现runge-kutta 5近似

该近似仅使用
t0
y
的值、开始时间
t0
、步长
h
和形式为
dy/dt=g(t,y)的微分方程
dgl
计算点
t0+h
处(未知)函数
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可能是另一个实现数字的对象)


但另一方面:我如何在围棋中表达这样的东西?在C++中,我可以使用运算符重载,但是在GO中不可能。

< P>确实,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
}
它可以编译,并且在使用正确类型的参数调用时应该可以工作,但是,我认为这是一种滥用

没有任何东西可以阻止您(除了运行时错误)使用此方法向标量添加向量,因为它们都将实现
数值
。最后,使用接口抽象将一无所获


在这种情况下,go理念将规定使用特定于类型的方法/函数。

您会遇到两个问题

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

修复了该问题,但创建了一个新问题

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


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

为了通用,您的
Add
方法必须采用
数值参数。处理此问题的正常方法是使用如下()的类型断言


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

您所说的“使用特定类型的方法/函数”到底是什么意思?你能举个例子吗?就像在中一样,你不会有一个通用的Add可以在Vec6F和其他类似数字的类型上工作。您可能需要addVec6F等等。因为我在大约2小时前需要(计算)结果,所以我更改了代码,改为使用float64的切片,这是提供这种访问器方法的一个激进版本。完整的代码是——它可以工作,但在我看来,它远不是一个好代码。访问器方法的问题如下:假设我必须使用复数。或者我只希望在另一个用例中使用整数值。提供一个访问器可能就不可能了,因为我不能只对向量/矩阵进行操作,也不能对多项式进行操作。Thx,这可能是我将要结束的解决方案,尽管我不喜欢类型断言。您可以转换为指针类型而不是
\u rhs.(Vec6F)
来保护不必要的副本,对吗?它必须是指针类型才能使类型断言工作。试着在上面的游乐场链接上更改它,看看我的意思-你会得到错误“不可能类型断言:Vec6F不实现数值(Add方法需要指针接收器)”“离题”:解决的微分方程是描述(简单)火星轨道的方程。有关快速“n”脏完整代码,请参阅
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
}