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

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

报告相同问题?

悬赏问题

  • ¥15 公交车和无人机协同运输
  • ¥15 stm32代码移植没反应
  • ¥15 matlab基于pde算法图像修复,为什么只能对示例图像有效
  • ¥100 连续两帧图像高速减法
  • ¥15 组策略中的计算机配置策略无法下发
  • ¥15 如何绘制动力学系统的相图
  • ¥15 对接wps接口实现获取元数据
  • ¥20 给自己本科IT专业毕业的妹m找个实习工作
  • ¥15 用友U8:向一个无法连接的网络尝试了一个套接字操作,如何解决?
  • ¥30 我的代码按理说完成了模型的搭建、训练、验证测试等工作(标签-网络|关键词-变化检测)