dongpu9852 2018-09-25 09:08
浏览 63
已采纳

Nocopy最小示例?

I've been trying to get a noCopy directive to work for one of my own structs, but I cannot get go vet to detect it.

I can get it to detect copying of sync.WaitGroup, and sync.Mutex, but not my own struct. This test file in the vet source doesn't even trigger with my go vet.

Or well, it finds some of the errors:

# command-line-arguments
./govet.go:56:6: no new variables on left side of :=
./govet.go:110:17: unsafe.Sizeof(mu) evaluated but not used
./govet.go:111:18: unsafe.Sizeof(mu) evaluated but not used
./govet.go:112:10: unsafe.Sizeof(mu) evaluated but not used

but the copylock detection doesn't find anything.

Did something change in go vet since this discussion at 1.4? I'm running go version go1.11 darwin/amd64.

  • 写回答

1条回答 默认 最新

  • dshw124502 2018-09-25 09:52
    关注

    First, copying locks is properly detected by go vet. Example:

    type My struct {
        l sync.Mutex
    }
    

    Usage:

    func main() {
        m := My{}
        m2 := m
        fmt.Println(m2)
    }
    

    Running go vet, the output is:

    ./play.go:25: assignment copies lock value to m2: main.My contains sync.Mutex
    ./play.go:26: call of fmt.Println copies lock value: main.My contains sync.Mutex
    

    So both cases (assigning and passing to fmt.Println()) were detected.

    This also means that the easiest way to make your struct a target of vet when copied, simply add a field of type sync.Mutex. This is a ready solution, although it consumes memory (sync.Mutex is not a zero-size struct). It doesn't matter whether you use this mutex or not (we didn't use it in the example above).

    In the discussion you referenced Rob Pike suggests to create a type:

    type noCopy struct{}
    func (*noCopy) Lock() {}
    

    And use a field of this type (either regular or embedded) to mark a struct non-copiable (and so make go vet scream if that happens).

    I don't know if this has ever worked, but currently it doesn't, because go vet checks for the sync.Locker interface, which also has an Unlock() method:

    type Locker interface {
            Lock()
            Unlock()
    }
    

    So if we create a noCopy type that implements sync.Locker (more precisely its pointer type), that will work:

    type noCopy struct{}
    
    func (*noCopy) Lock()   {}
    func (*noCopy) Unlock() {}
    
    type By struct {
        noCopy noCopy
    }
    

    Testing it:

    func main() {
        b := By{}
        b2 := b
        fmt.Println(b2)
    }
    

    Running go vet:

    ./play.go:29: assignment copies lock value to b2: main.By contains main.noCopy
    ./play.go:30: call of fmt.Println copies lock value: main.By contains main.noCopy
    

    Here are some changes related to go vet and noCopy:

    Go 1.7

    Go 1.8

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

报告相同问题?

悬赏问题

  • ¥60 版本过低apk如何修改可以兼容新的安卓系统
  • ¥25 由IPR导致的DRIVER_POWER_STATE_FAILURE蓝屏
  • ¥50 有数据,怎么建立模型求影响全要素生产率的因素
  • ¥50 有数据,怎么用matlab求全要素生产率
  • ¥15 TI的insta-spin例程
  • ¥15 完成下列问题完成下列问题
  • ¥15 C#算法问题, 不知道怎么处理这个数据的转换
  • ¥15 YoloV5 第三方库的版本对照问题
  • ¥15 请完成下列相关问题!
  • ¥15 drone 推送镜像时候 purge: true 推送完毕后没有删除对应的镜像,手动拷贝到服务器执行结果正确在样才能让指令自动执行成功删除对应镜像,如何解决?