2017-02-14 81 views
7

我想我明白了答案从here但为了以防万一,我要明确地询问以下(我的道歉,如果你认为它是同样的问题,但对我来说,感觉不同在关注):复制引用指针或值

func f() *int { 
    d := 6 
    pD := new(int) 
    pD = &d // option 1 
    *pD = d // option 2 
    return pD 
} 

,我只是复制引用作为指针的第一个选项是性能的角度来看,更优化的(这是教育的猜测,但它似乎是显而易见的)。我更喜欢这种方法/模式。

第二种办法(浅)复印件(?)来代替。我认为这种方法,因为它复制,我不担心GC扫描'd'的实例。由于我的不安全感(或者作为初学者无知),我经常使用这种方法。

我所关心的(或者更加不安全的)是,在第一种方法中('d'的地址被转移),GC会认识到它('d'变量)被一个指针容器,因此它不会被扫描?因此,使用这种方法是安全的吗?即我可以安全地传递从func'f()'返回的指针'pD'来获取应用程序的整个生命周期吗?

参考:https://play.golang.org/p/JWNf5yRd_B

回答

9

有没有更好的地方去寻找比官方文档:

func NewFile(fd int, name string) *File { 
    if fd < 0 { 
     return nil 
    } 
    f := File{fd, name, nil, 0} 
    return &f 
} 

需要注意的是,不像C,这是完全确定,返回一个局部变量的地址 ;函数返回后,与该变量相关联的存储器仍然存在 。事实上,取文字的复合地址 会在每次评估时分配一个新的实例,因此我们 可以组合这些最后两行。

(来源:"Effective Go"

所以第一个选项(返回一个指针指向一个局部变量)是绝对安全的,甚至鼓励。通过执行escape analysis,编译器可以告诉变量转义其本地作用域,并将其分配到堆上。

3

总之:第

第一:有没有 “引用”,在围棋。现在忘了这个想法,否则你会伤害自己。真。对“通过参考”的思考显然是错误的。

二:性能是完全一样的。现在忘掉这种纳米优化。特别是在处理int时。当且仅当您遇到性能问题时:测量,然后进行优化。它可能会直观地吸引人的思考:“处理8个字节的小指针必须比复制30个甚至100个字节的结构快得多。”这不是,至少不是那么简单。

三:只写它func f() *int { d := 6; return &d; }。这里不需要做任何奇特的舞蹈。

四:选项2时,INT的“深层复制”。但是这可能是误导,因为没有int的“浅拷贝”,所以我不确定我是否理解你在这里问的问题。 Go没有深层复制和浅层复制的概念。如果您复制指针值,则会复制指针值。你记得第一点? Go中没有提及。指针值是一个值,如果您复制了指针值的副本。这样的副本对所指向的值完全没有任何影响,特别是它不做副本。这将暗示Go中的副本不“深”。谈论Go时忘掉深浅拷贝。 (当然你也可以实现其进行自定义对象的“深层复制”功能)

第五:去有正常工作垃圾收集器。它的作用完全没有区别:当一个对象是活的时候,它不会被收集,一旦它被收集,它就会被收集起来。你可以传递,返回,复制,移交,取地址,取消引用指针或任何你喜欢的东西,这没关系。 GC工作正常。 (除非你故意使用软件包不安全的方式寻找痛苦和错误。)