dsgni26260 2019-08-10 10:22
浏览 38
已采纳

如何使用界面定义安全划分并进行反映?

I want to define a safe division like:

func safeDivide(a, b interface{}) interface{} {
    if b == 0 {
        return 0
    }
    return a / b
}

Obviously, this function does not work. we can not divide interface. One solution is to judge the type of input and do the division.

switch reflect.ValueOf(x).Kind() {
    case reflect.Int:
    // balabala...

However it looks redundadnt, I must deal every case.

So if I could use reflect to guarantee the type of inputs? I have tried reflect.TypeOf() but failed.

By the way, I notice this:

a := uint32(0)
ifZero(a) // outputs "no"

func ifZero(a interface{}) {
    if a == 0 {
        log.Println("yes")
        return
    }
    log.Println("no")
}

That means golang itself cannot deal the type issue, right?

  • 写回答

1条回答 默认 最新

  • doucu9677 2019-08-11 00:20
    关注

    As you noted in a comment, now you know why (some) people want generics in Go. :-)

    For this particular case, you're probably better off just writing a safeDivideInt function:

    // a/b, but 0 if b == 0
    func safeDivideInt(a, b int64) int64 {
        if b == 0 {
            return 0
        }
        return a / b
    }
    

    and a similar safeDivideUint function (using uint64) ... and, if you need it,1 a safeDivideFloat function, e.g.:

    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
    }
    

    and then yet again for complex, if you want.

    But: there's no easy way to make the Go compiler call one or the other for you. You can write your interface-based function the way you did, and then do type-switching on the various arguments, but it gets quite long as you have to handle all possible combinations. The combinatorial effect is painful no matter how you reduce it. Using reflect and its type-kind interface does not help here as you still have five int types, five uint types (or six if you include uintptr), the two float types, and the two complex types. (It's not clear to me that allowing either of the Uintptr or UnsafePointer Kinds in your divide function makes any sense at all.)

    It might, however, make more sense—depending on context—to define your own interface. Here's a working toy example on the Go Playground. I didn't bother putting in Uint and Complex types.


    1Note that a runtime 1.0 / 0.0 is +Inf. The Go specification says:

    The result of a floating-point or complex division by zero is not specified beyond the IEEE-754 standard; whether a run-time panic occurs is implementation-specific.

    but IEEE-754 calls for Inf and NaN results by default, with exceptions being optional, so I assume this means that the default in Go is no exception raised, meaning "no panic", as well. See, e.g., this Wikipedia entry from which I quote a bit here:

    Arithmetic exceptions are (by default) required to be recorded in "sticky" status flag bits. ... By default, an operation always returns a result according to specification without interrupting computation. For instance, 1/0 returns +∞, while also setting the divide-by-zero flag bit (this default of ∞ is designed so as to often return a finite result when used in subsequent operations and so be safely ignored).

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 如何绘制动力学系统的相图
  • ¥15 对接wps接口实现获取元数据
  • ¥20 给自己本科IT专业毕业的妹m找个实习工作
  • ¥15 用友U8:向一个无法连接的网络尝试了一个套接字操作,如何解决?
  • ¥30 我的代码按理说完成了模型的搭建、训练、验证测试等工作(标签-网络|关键词-变化检测)
  • ¥50 mac mini外接显示器 画质字体模糊
  • ¥15 TLS1.2协议通信解密
  • ¥40 图书信息管理系统程序编写
  • ¥20 Qcustomplot缩小曲线形状问题
  • ¥15 企业资源规划ERP沙盘模拟