dsvbtgo639708 2018-02-22 02:48 采纳率: 0%
浏览 33
已采纳

类型转换运算符重载作为'GO'中的全局函数

What I would like to do is as follows. I have an application code (say, MyApp), one package (perhaps) from a third party, and the other from gccgo. They are particularly golang.org/sys/unix and syscall, respectively.

MyApp tries to assign a syscall.Timespec variable to an unix.Timespec variable. That is mismatch when I use syscall from gccgo while it is not when the syscall is from Gc.

I would like to avoid changing the two libraries. I would like to make a change to MyApp. However, the patch will not go to the upstream of MyApp. I, or my employer, should maintain the patch locally. That says if the git repo of MyApp is updated, we would need to pull it again and apply another patch to it.

In that sense, I would like to try to minimize the efforts for the future maintenance.

The mismatch itself is as follows, if I simplify:

// example.go
package main

import "fmt"

type aliased_int int

type SrcStruct struct {
    x aliased_int
}

type DstStruct struct {
    x int
}

func main() {
    src := SrcStruct{x: 30}
    dst := DstStruct(src)
    fmt.Println(dst.x)
}

The code above caused a compile error due to the "x aliased_int" line. If it were "x int," the code is compiled successfully.

If this were a C++ application and libraries, I would define a type-casting operator overloading from SrcStruct to DstStruct. (%p.s. this won't work because C++ does not allow type-casting operator overloading as a global function. However, I wanted to know such a solution is available in Go.)

I am not sure if I could do the same in Go. (i.e. defining a custom type-casting operator as a global function or so) If not, what is the best for this situation when it comes to Go programming?

%P.S.

Michael Hampton kindly pointed out that gccgo's Timespec is different from Google Go compiler, Gc's Timespec. The difference is, however, gccgo uses an alias to int64 such as Timespec_sec_t or Timespec_nsec_t.

Gccgo's Timespec is defined in Gccgo's package. Gc's Timespec is included in MyApp's source tree. MyApp assumes that Timespec is the same as Gc defined. I would like only touch MyApp code minimally.

  • 写回答

1条回答 默认 最新

  • douxie5176 2018-02-22 03:28
    关注

    Well, first, your code sample doesn't seem to accurately reflect the problem you described in prose, so I'll begin by ignoring it for the moment and writing code more similar to what you actually described:

    package main
    
    import (
        "fmt"
        "reflect"
        "syscall"
    
        "golang.org/x/sys/unix"
    )
    
    func main() {
        src := syscall.Timespec{3, 4}
        dst := unix.Timespec(src)
    
        fmt.Printf("%v is a %s
    ", dst, reflect.TypeOf(dst))
    }
    

    We're just doing a simple type conversion, which works because the fields in both structs have exactly the same names and types.

    {3 4} is a unix.Timespec
    

    syscall.Timespec

    type Timespec struct {
            Sec  int64
            Nsec int64
    }
    

    unix.Timespec

    type Timespec struct {
        Sec  int64
        Nsec int64
    }
    

    You can copy these with a simple type conversion because the structs are exactly the same and the fields are exported.

    Note that you can do this in cgo, but not in gccgo, which rejects the type conversion. The language specification states that this type conversion should work (as the structs have identical underlying types).

    The obvious workaround is to deep copy the struct yourself, something like:

        dst := unix.Timespec{src.Sec, src.Nsec}
    

    But this doesn't work because gccgo complains:

    # command-line-arguments
    ./x.go:13:29: error: incompatible type for field 1 in struct construction (cannot use type syscall.Timespec_sec_t as type int64)
         dst := unix.Timespec{src.Sec, src.Nsec}
                                 ^
    ./x.go:13:38: error: incompatible type for field 2 in struct construction (cannot use type syscall.Timespec_nsec_t as type int64)
         dst := unix.Timespec{src.Sec, src.Nsec}
                                          ^
    

    So we see the root of the problem is that gccgo's syscall.Timespec is not identical to unix.Timespec, and it's not even identical to the syscall.Timespec in the cgo standard library.

    You're not the first person to run into this issue either. Unfortunately that issue was closed without an obvious workaround that would work for you. Your best bet, of course, is to rewrite the offending code to not use the syscall package. Or stop using gccgo.


    The example code you posted in your question is a bit different. In this case the fields have different types. Go doesn't really care that aliased_int is "actually" an int underneath. It treats them as separate types, because in Go the predeclared numeric types are also considered defined types, and thus you can't use a simple type conversion here. The spec indicates under what circumstances type conversions are allowed, and this doesn't appear to fall into any of them.

    You'll have to do a deep copy yourself. There are numerous Go libraries to help with doing deep copies of structs.

    The other problem in this code is that the struct fields are unexported. You can't really deep copy them at all. If you exported the fields, then you could.

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

报告相同问题?

悬赏问题

  • ¥15 banner广告展示设置多少时间不怎么会消耗用户价值
  • ¥16 mybatis的代理对象无法通过@Autowired装填
  • ¥15 可见光定位matlab仿真
  • ¥15 arduino 四自由度机械臂
  • ¥15 wordpress 产品图片 GIF 没法显示
  • ¥15 求三国群英传pl国战时间的修改方法
  • ¥15 matlab代码代写,需写出详细代码,代价私
  • ¥15 ROS系统搭建请教(跨境电商用途)
  • ¥15 AIC3204的示例代码有吗,想用AIC3204测量血氧,找不到相关的代码。
  • ¥20 CST怎么把天线放在座椅环境中并仿真