我是一名 C++ 高级程序员。我目前正在做一些 Go 编程。我真正想念的唯一功能是 const 限定符。在go中,如果你想修改一个对象,你就传递它的指针。如果您不想修改它,则按值传递它。但是如果结构很大,你应该通过指针传递它,它覆盖了无修改功能。更糟糕的是,您可以按值传递一个对象,但如果它包含一个指针,您实际上可以修改其内容,这会带来可怕的竞争条件危险。某些语言类型(如地图和切片)具有此功能。这发生在一种应该为并发构建的语言中。所以避免修改的问题在 Go 中真的不存在,你应该传递小对象不包含指针的 (您必须知道对象不包含指针)按值,如果它们不会被修改。
使用 const,您可以通过 const 指针传递对象,而不必担心修改。类型安全是关于拥有允许速度并防止与类型相关的错误的契约。执行此操作的另一个功能是 const 限定符。
C/C++ 中的 const 类型限定符有多种含义。当应用于变量时,意味着该变量是不可变的。这是一项有用的功能,也是 Go 所缺少的功能,但它似乎不是您正在谈论的功能。
您正在谈论 const 可以用作函数的部分强制契约的方式。函数可以为指针参数提供 const 限定符,以表示该函数不会使用该指针更改任何值。(当然,除非该函数使用强制转换(const_castC++ 中的 a)。或者,在 C++ 中,指针指向声明的字段mutable。)
Go 有一个非常简单的类型系统。许多语言都有复杂的类型系统,您可以通过编写类型来强制程序的正确性。在许多情况下,这意味着大量编程涉及编写类型声明。Go 采用了不同的方法:大多数编程涉及编写代码,而不是类型。您可以通过编写正确的代码来编写正确的代码,而不是通过编写捕获编写错误代码的情况的类型来编写正确的代码。如果您想捕获不正确的代码,您可以编写分析器,就像go vet查找代码中无效的情况一样。为 Go 编写此类分析器比为 C/C++ 编写要容易得多,因为该语言更简单。
这种方法有优点也有缺点。Go 在这里做出了明确的选择:编写代码,而不是类型。这不是每个人的正确选择。
请将其视为扩展评论。我不是任何编程语言设计师,因此无法在这里深入讨论细节,但我会作为 C++ 的长期开发人员和 Go 的短期开发人员提出我的看法。
\n\n对于编译器来说,Const 是一项重要的功能,因此必须确保它是否为用户实现它提供了足够的优势,并且不会牺牲语法的简单性。你可能认为这只是一个const我们正在讨论的一个限定符,但看看 C++ 本身,它并不那么容易 \xe2\x80\x93 有很多警告。
你说的const是一份合同,你在任何情况下都不应该修改它。反对使用只读接口的论点之一是您可以将其转换为原始类型并执行您想要的任何操作。你当然可以。同样的方式,你可以使用 C++ 对合约竖起中指const_cast。由于某种原因它被添加到语言中,不确定我是否应该为此感到自豪,我已经使用过它一两次。
C++ 中还有另一个修饰符,允许您放宽契约 \xe2\x80\x93 mutable。有人意识到const结构实际上可能需要修改一些字段,通常是保护内部变量的互斥体。我想你在 Go 中需要类似的东西才能实现线程安全结构。
当它出现时,简单的const int x人可以很容易地遵循。但随后指针就会介入,人们真的会感到困惑。const int * x, int * const x, const int * const x\xe2\x80\x93 这些都是 的有效声明x,每个声明都有不同的合同。我知道选择正确的方法并不是一件复杂的事情,但是您作为一名高级 C++ 程序员的经验是否告诉您人们广泛理解这些并且始终使用正确的方法?我什至没有提到过类似的事情const int * const * * * const * const x。这让我大吃一惊。
在讨论第四点之前,我想引用以下内容:
\n\n\n\n\n更糟糕的是,您可以按值传递对象,但如果它包含指针,\n您实际上可以修改其内容
\n
这是一个有趣的指控。C++ 中也存在同样的问题;更糟糕的是 \xe2\x80\x93 即使你将 object 声明为 const 它也存在,这意味着你不能用简单的方法解决问题const限定符解决问题。请参阅下一点:
根据 3 和指针,表达非常正确的合同并不那么容易,有时事情会出乎意料。这段代码让一些人感到惊讶:
\n\nstruct S {\n int *x;\n};\n\nint main() {\n int n = 7;\n const S s = {&n}; // don\'t touch s, it\'s read only!\n *s.x = 666; // wait, what? s is const! is satan involved?\n}\nRun Code Online (Sandbox Code Playgroud)\n\n我确信您很自然地理解为什么上面的代码可以编译。这是你无法修改的指针值(它指向的地址),而不是它后面的值。你必须承认周围有人会扬起眉毛。
我不知道这是否有意义,但我一直在 C++ 中使用 const。非常精准。正在思考它。不确定它是否拯救了我的屁股,但在转向 Go 之后,我必须承认我从未错过过它。考虑到所有这些边缘情况和例外,我真的相信像 Go 这样的极简语言的创建者会决定跳过这个。
\n\n\n\n\n类型安全是指拥有一个允许速度并防止与类型相关的错误的合约。
\n
同意。例如,在 Go 中,我喜欢类型之间没有隐式转换。这确实阻止了我遇到与类型相关的错误。
\n\n\n\n\n另一个可以实现此目的的功能是 const 限定符。
\n
根据我的整个答案 \xe2\x80\x93 我不同意。如果一般的 const 合约确实可以做到这一点,那么简单的 const 限定符是不够的。然后你需要一个mutable,也许是一种 const_cast 功能,但仍然 \xe2\x80\x93 它可能会让你对保护产生误导性的信念,因为很难理解到底什么是常量。
希望一些语言创建者能够设计一种在我们的代码中定义常量的完美方法,然后我们将在 Go 中看到它。或者转向新语言。但就我个人而言,我并不认为C++的方式是一种特别好的方式。
\n\n(另一种选择是遵循函数式编程范例,它希望看到所有“变量”都是不可变的。)
\n