草庐IT

pointers - Golang 复制包含指针的结构

coder 2023-06-27 原文

TL; 博士
由于投票不足,缺乏答案和评论,我认为需要 tl;dr。

如何在 golang 中创建一个包含指针的结构,然后将其安全地按值传递给其他函数? (安全我的意思是不必担心这些函数可以取消对所述指针的引用并更改其指向的变量)。



如果您要给出的答案是“复制函数”,那么如何删除原始复制构造函数/运算符?用我的自定义复制功能覆盖它?或者以其他方式阻止人们使用它?

在 golang 中,我可以有一个包含指向动态分配变量的指针的结构。

我还可以将这些结构的实例传递给“复制”它们的函数。

但是,我无法覆盖或删除内置复制运算符。这意味着,理论上,我可以编写如下代码:

import (
        "fmt"
)

type A struct {
        a * int
}

func main() {
        var instance A
        value := 14
        instance.a = &value
        fmt.Println(*instance.a) // prints 14
        mutator(instance)
        fmt.Println(*instance.a) // prints 11 o.o
}

func mutator(instance A) {
        *instance.a = 11
        fmt.Println(*instance.a)
}

这种类型的代码在这里显然有点荒谬。然而,假设成员字段“a”是一个复杂的结构,访问它的函数可能会尝试修改它。

这也可能是合乎情理的,一旦函数“mutator”被调用,程序员可能想要继续使用他的 A 实例,并且(假设他不一定对结构进行编码或了解其内部结构)甚至可能假设因为他传递了一个副本而不是一个指针,他的 A 实例将保持不变。

现在,有几 (3) 种流行的语言允许程序员考虑分配和操作不是 golang 的内存。我不知道 Rust 或 C,所以我将避免在 C++ 中如何解决这个问题:

a) 假设我是 A 类的设计者,我可以构建一个复制构造函数,生成以下代码:
#include <iostream>

    class A {
    public:
            int * a;
            A(int value): a(new int{value}) {}
            A(const A & copyFrom): a(new int{*copyFrom.a}) {}
    };

    void mutator(A instance) {
            *instance.a = 11;
            std::cout << *instance.a << "\n";
    }


    int main() {
            A instance{14};
            std::cout << *(instance.a) << "\n";
            mutator(instance);
            std::cout << *instance.a << "\n";
    }

这允许复制我的类的一个实例,并添加一个警告,即指针也被重新分配。

b) 假设我是 A 类的设计者并且不想构建复制构造函数(比如 a 指向的任何东西都可能非常大,或者 A 经常在性能临界条件下用作只读对象)但想要构建确保复制的任何赋值都不能修改 a 指向的值(但仍然允许人们通过将其分配给新值来修改 a)我可以这样编写我的类:
class A {
public:
        const int * a;
        A(int value): a(new const int{value}) {}
};

这将使以下代码无法编译:
void mutator(A instance) {
        *instance.a = 11;
        std::cout << *instance.a << "\n";
}


int main() {
        A instance{14};
        std::cout << *(instance.a) << "\n";
        mutator(instance);
        std::cout << *instance.a << "\n";
}

但是下面的代码可以编译得很好:
void mutator(A instance) {
        instance.a = new const int{11};
        std::cout << *instance.a << "\n";
}


int main() {
        A instance{14};
        std::cout << *(instance.a) << "\n";
        mutator(instance);
        std::cout << *instance.a << "\n";
}

现在,请注意,这是 C++ 的“面向对象”(eegh)设计的典型特征。如果我可以在函数签名中有某种规则来保证不会修改传递给它的 A 的实例或一种方法来动态声明 A 的实例“const”并“保护”它,我会更喜欢分配的字段(不仅是静态的)防止重新分配。

然而,虽然解决方案可能并不完美,但它是一个解决方案。它让我对我的 A 实例的“所有权”有一个清晰的认识。

在 golang 中,似乎包含指针的实例的任何“副本”基本上对所有人都是免费的,即使结构的作者有这样的意图,也不能安全地传递它。

我能想到的一件事是有一个“复制”方法,它返回一个全新的结构实例(类似于上面例子中的复制构造函数)。但是如果没有删除复制构造函数/运算符的能力,就很难确保人们会使用和/或注意到它。

老实说,golang 甚至允许在不使用“不安全”包或类似的东西的情况下重写指针的内存地址,这对我来说似乎很奇怪。

像许多其他操作一样简单地禁止此类操作不是更有意义吗?

考虑到“追加”的工作方式,作者的意图似乎很明显是倾向于将新变量重新分配给一个指针,而不是改变它之前指向的变量。然而,虽然这很容易通过像 slice 或数组这样的内置结构来实现,但似乎很难用自定义结构来实现(至少没有将所述结构包装在一个包中)。

我是否忽略了在 golang 中进行复制构造(或禁止复制)的方法?在内存和时间允许的情况下,鼓励重新分配而不是突变真的是作者的初衷吗?如果是这样,为什么改变动态分配的变量如此容易?有没有办法用结构或文件而不是完整的包来模拟私有(private)/公共(public)行为?有没有其他方法可以通过具有我忽略的指针的结构来强制执行某种所有权的外观?

最佳答案

How can I create a struct in golang, which contains a pointer, then safely pass it by value to other functions ? (By safely I mean without having to worry that those functions can dereference said pointer and change the variable its pointing to).



使用带有未导出字段的导出包类型。例如,
src/ptrstruct/ptrstruct.go :
package ptrstruct

type PtrStruct struct {
    pn *int
}

func New(n int) *PtrStruct {
    return &PtrStruct{pn: &n}
}

func (s *PtrStruct) N() int {
    return *s.pn
}

func (s *PtrStruct) SetN(n int) {
    *s.pn = n
}

func (s *PtrStruct) Clone() *PtrStruct {
    // make a deep clone
    t := &PtrStruct{pn: new(int)}
    *t.pn = *s.pn
    return t
}
src/ptrstruct.go :
package main

import (
    "fmt"

    "ptrstruct"
)

func main() {
    ps := ptrstruct.New(42)
    fmt.Println(ps.N())
    pc := ps.Clone()
    fmt.Println(pc.N())
    pc.SetN(7)
    fmt.Println(pc.N())
    fmt.Println(ps.N())
}

输出:
src $ go run ptrstruct.go
42
42
7
42
src $ 

If the answer you are going to give is "Copy functions" then how can I delete the original copy constructor/operator ? Override it with me custom copy function ? Or otherwise discourage people from using it ?



停止用 C++ 编程;开始在 Go 中编程。按照设计,Go 不是 C++。

“复制构造函数/运算符”和“用自定义函数覆盖它”是 C++ 概念。

引用:

The Go Programming Language Specification

Blocks

Declarations and scope

Exported identifiers

关于pointers - Golang 复制包含指针的结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43622388/

有关pointers - Golang 复制包含指针的结构的更多相关文章

  1. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  2. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  3. ruby - 检查字符串是否包含散列中的任何键并返回它包含的键的值 - 2

    我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案

  4. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

  5. ruby-on-rails - 一般建议和推荐的文件夹结构 - Sinatra - 2

    您将如何构建一个简单的Sinatra应用程序?我正在制作,我希望该应用具有以下功能:“应用程序”更像是一个包含所有信息的管理仪表板。然后另一个应用程序将通过REST访问信息。我还没有创建仪表板,只是从数据库中获取东西session和身份验证(尚未实现)您可以上传图片,其他应用可以显示这些图片我已经使用RSpec创建了一个测试文件通过Prawn生成报告目前的设置是这样的:app.rbtest_app.rb因为我实际上只有应用程序和测试文件。到目前为止,我已经将Datamapper用于ORM,将SQLite用于数据库。这是我的第一个Ruby/Sinatra项目,所以欢迎任何和所有建议-我应

  6. ruby-on-rails - 使用包含多个关联和单独的条件 - 2

    我的Gallery模型中有以下查询:media_items.includes(:photo,:video).rank(:position_in_gallery)我的图库模型有_许多媒体项,每个都有一个照片或视频关联。到目前为止,一切正常。它返回所有media_items包括它们的photo或video关联,由media_item的position_in_gallery属性排序。但是我现在需要将此查询返回的照片限制为仅具有is_processing属性的照片,即nil。是否可以进行相同的查询,但条件是返回的照片等同于:.where(photo:'photo.is_processingIS

  7. ruby - 我怎样才能只写一次 "Text"并同时检查 path_info 是否包含 'A' ? - 2

    -if!request.path_info.include?'A'%{:id=>'A'}"Text"-else"Text"“文本”写了两次。我怎样才能只写一次并同时检查path_info是否包含“A”? 最佳答案 有两种方法可以做到这一点。使用部分,或使用content_forblock:如果“文本”较长,或者是一个重要的子树,您可以将其提取到一个部分。这会使您的代码变干一点。在给出的示例中,这似乎有点矫枉过正。在这种情况下更好的方法是使用content_forblock,如下所示:-if!request.path_info.inc

  8. Ruby,使用包含 TK GUI 的 ocra 部署一个 exe - 2

    Ocra无法处理需要“tk”的应用程序require'tk'puts'nope'用奥克拉http://github.com/larsch/ocra不起作用(如链接中的一个问题所述)问题:https://github.com/larsch/ocra/issues/29(Ocra是1.9的"new"rubyscript2exe,本质上它用于将rb脚本部署为可执行文件)唯一的问题似乎是缺少tcl的DLL文件我不认为这是一个问题据我所知,问题是缺少tk的DLL文件如果它们是已知的,则可以在执行ocra时将它们包括在内有没有办法知道tk工作所需的DLL依赖项? 最佳答

  9. ruby - 允许主机名包含下划线的 URI.parse 的替代方法 - 2

    我正在使用DMOZ的listofurltopics,其中包含一些具有包含下划线的主机名的url。例如:608609TheOuterHeaven610InformationandimagegalleryofMcFarlane'sactionfiguresforTrigun,Akira,TenchiMuyoandotherJapaneseSci-Fianimations.611Top/Arts/Animation/Anime/Collectibles/Models_and_Figures/Action_Figures612虽然此url可以在网络浏览器中使用(或者至少在我的浏览器中可以使用:

  10. ruby - 如何在 ruby​​ 中复制目录结构,不包括某些文件扩展名 - 2

    我想编写一个ruby​​脚本来递归复制目录结构,但排除某些文件类型。因此,给定以下目录结构:folder1folder2file1.txtfile2.txtfile3.csfile4.htmlfolder2folder3file4.dll我想复制这个结构,但不包含.txt和.cs文件。因此,生成的目录结构应如下所示:folder1folder2file4.htmlfolder2folder3file4.dll 最佳答案 您可以使用查找模块。这是一个代码片段:require"find"ignored_extensions=[".cs"

随机推荐