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 ansys fluent计算闪退
  • ¥15 有关wireshark抓包的问题
  • ¥15 需要写计算过程,不要写代码,求解答,数据都在图上
  • ¥15 向数据表用newid方式插入GUID问题
  • ¥15 multisim电路设计
  • ¥20 用keil,写代码解决两个问题,用库函数
  • ¥50 ID中开关量采样信号通道、以及程序流程的设计
  • ¥15 U-Mamba/nnunetv2固定随机数种子
  • ¥15 vba使用jmail发送邮件正文里面怎么加图片
  • ¥15 vb6.0如何向数据库中添加自动生成的字段数据。