为了账号安全,请及时绑定邮箱和手机立即绑定

如何使用接口和反射来定义安全划分?

如何使用接口和反射来定义安全划分?

Go
墨色风雨 2023-07-10 16:44:37
我想定义一个安全划分,例如:func safeDivide(a, b interface{}) interface{} {    if b == 0 {        return 0    }    return a / b}显然,这个功能是行不通的。我们不能划分接口。一种解决方案是判断输入的类型并进行划分。switch reflect.ValueOf(x).Kind() {    case reflect.Int:    // balabala...不过看起来多余,我必须处理好每一个案件。那么我是否可以使用反射来保证输入的类型?我尝试过reflect.TypeOf()但失败了。顺便说一句,我注意到这一点:a := uint32(0)ifZero(a) // outputs "no"func ifZero(a interface{}) {    if a == 0 {        log.Println("yes")        return    }    log.Println("no")}这意味着 golang 本身无法处理类型问题,对吗?
查看完整描述

1 回答

?
慕森王

TA贡献1777条经验 获得超3个赞

现在您知道为什么(某些)人们想要在 Go 中使用泛型。:-)

对于这种特殊情况,您最好只编写一个safeDivideInt函数:

// a/b, but 0 if b == 0

func safeDivideInt(a, b int64) int64 {

    if b == 0 {

        return 0

    }

    return a / b

}

和一个类似的safeDivideUint函数(使用uint64)...并且,如果需要的话,1个safeDivideFloat函数,例如:


func safeDivideFloat(a, b float64) float64 {

    // decide if you want 0/0 handled differently

    // decide if you want to check for b being Inf or NaN

    // etc.

    if b == 0 {

        return 0

    }

    return a / b

}

如果你愿意的话,然后再一次进行复杂的处理。

但是:没有简单的方法可以让 Go 编译器为您调用其中之一。您可以按照您的方式编写基于接口的函数,然后对各种参数进行类型切换,但是由于您必须处理所有可能的组合,因此它会变得很长。无论如何减少,组合效应都是痛苦的。使用reflect和 它的 type-kind 接口在这里没有帮助,因为您仍然有五种int类型,五种uint类型(如果包含 则为六种类型uintptr),两种float类型和两种complex类型。(我不清楚在除法函数中允许使用 或UintptrsUnsafePointer Kind是否有任何意义。)

然而,根据上下文,定义您自己的界面可能更有意义。 这是 Go Playground 上的一个工作玩具示例。我没有费心放入 Uint 和 Complex 类型。


1请注意,运行时 1.0 / 0.0 是+Inf。Go规范说:

浮点或复数除以零的结果未在 IEEE-754 标准之外指定;是否发生运行时恐慌是特定于实现的。

但 IEEE-754 默认情况下要求 Inf 和 NaN 结果,异常是可选的,所以我认为这意味着 Go 中的默认情况下不会引发异常,也意味着“无恐慌”。

算术异常(默认情况下)需要记录在“粘性”状态标志位中。...默认情况下,操作始终根据规范返回结果,而不会中断计算。例如,1/0 返回 +∞,同时还设置被零除标志位(这个默认值 ∞ 的设计目的是为了在后续操作中使用时经常返回有限结果,因此可以安全地忽略)。


查看完整回答
反对 回复 2023-07-10
  • 1 回答
  • 0 关注
  • 81 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信