为了账号安全,请及时绑定邮箱和手机立即绑定

Go 没有 const 限定符的基本原理是什么?

Go 没有 const 限定符的基本原理是什么?

Go
青春有我 2021-11-22 16:08:51
我是一名 C++ 高级程序员。我目前正在做一些 Go 编程。我真正想念的唯一功能是 const 限定符。在go中,如果你想修改一个对象,你就传递它的指针。如果您不想修改它,则按值传递它。但是如果结构很大,你应该通过指针传递它,它覆盖了无修改功能。更糟糕的是,您可以按值传递一个对象,但如果它包含一个指针,您实际上可以修改其内容,这会带来可怕的竞争条件危险。某些语言类型(如地图和切片)具有此功能。这发生在一种应该为并发构建的语言中。所以避免修改的问题在 Go 中真的不存在,你应该传递不包含指针的小对象 (您必须知道对象不包含指针)按值,如果它们不会被修改。使用 const,您可以通过 const 指针传递对象,而不必担心修改。类型安全是关于拥有允许速度并防止与类型相关的错误的契约。执行此操作的另一个功能是 const 限定符。
查看完整描述

2 回答

?
长风秋雁

TA贡献1757条经验 获得超7个赞

请将其视为扩展评论。我不是任何编程语言设计师,所以不能深入这里的细节,但我会提出我作为 C++ 长期开发人员和 Go 短期开发人员的看法。

Const 是编译器的一项重要功能,因此必须确保它是否为用户提供了足够的优势来实现它,并且不会牺牲语法的简单性。您可能认为这只是const我们所谈论的限定词,但看看 C++ 本身,这并不容易——有很多警告。

  1. 你说的const是合同,在任何情况下都不能修改。您反对使用只读接口的论据之一是您可以将其转换为原始类型并做任何您想做的事情。你当然可以。与您可以在 C++ 中使用const_cast. 出于某种原因,它被添加到语言中,我不确定我是否应该为此感到自豪,我已经使用过一两次了。

  2. C++ 中有另一个修饰符可以让你放松契约—— mutable. 有人意识到const结构实际上可能需要修改一些字段,通常是保护内部变量的互斥锁。我想你需要在 Go 中使用类似的东西才能实现线程安全的结构。

  3. 说到简单,const int x人们可以很容易地跟上。但是随后指针跳了进来,人们真的很困惑。const int * xint * const xconst int * const x– 这些都是 的有效声明x,每个声明都有不同的合同。我知道选择正确的方法并不是一门火箭科学,但是您作为高级 C++ 程序员的经验是否告诉您人们广泛理解这些并且总是使用正确的方法?我什至没有提到像const int * const * * * const * const x. 它让我大吃一惊。

在进入第 4 点之前,我想引用以下内容:

更糟糕的是,您可以按值传递一个对象,但如果它包含一个指针,您实际上可以修改其内容

现在这是一个有趣的指控。在 C++ 中也有同样的问题;更糟糕的是——即使你将 object 声明为 const,它也存在,这意味着你不能用简单的const限定符来解决问题。看下一点:

  1. 根据 3 和指针,表达非常正确的合同并不容易,有时事情会出乎意料。这段代码让一些人感到惊讶:

struct S {

    int *x;

};


int main() {

    int n = 7;

    const S s = {&n}; // don't touch s, it's read only!

    *s.x = 666; // wait, what? s is const! is satan involved?

}

我敢肯定,为什么上面的代码会编译对您来说是很自然的。它是您无法修改的指针值(它指向的地址),而不是它背后的值。你必须承认周围有人会扬起眉毛。


我不知道这是否有意义,但我一直在 C++ 中使用 const。非常精准。正在考虑它。不确定它是否曾经救过我的屁股,但是在搬到 Go 之后我必须承认我从未错过它。考虑到所有这些边缘情况和例外,我真的相信像 Go 这样的极简语言的创造者会决定跳过这个。


类型安全是关于拥有允许速度并防止与类型相关的错误的契约。


同意。例如,在 Go 中,我喜欢类型之间没有隐式转换。这确实阻止了我遇到与类型相关的错误。


执行此操作的另一个功能是 const 限定符。


根据我的整个回答——我不同意。一般的 const 合同肯定会做到这一点,一个简单的 const 限定符是不够的。然后你需要mutable一个,也许是一种 const_cast 特性,但它仍然会让你对保护产生误导性的看法,因为很难理解到底什么是常量。


希望一些语言创造者能设计出一种完美的方式在我们的代码中定义常量,然后我们会在 Go 中看到它。或者转移到新语言。但就我个人而言,我认为 C++ 的方式并不是特别好的方式。


(另一种选择是遵循函数式编程范式,它希望看到他们所有的“变量”都是不可变的。)


查看完整回答
反对 回复 2021-11-22
?
慕田峪9158850

TA贡献1794条经验 获得超7个赞

C/C++ 中的 const 类型限定符有多种含义。当应用于变量时,意味着该变量是不可变的。这是一项有用的功能,也是 Go 所缺少的功能,但它似乎不是您在谈论的功能。

您正在谈论可以将 const 用作函数的部分强制合同的方式。函数可以为指针参数提供 const 限定符,这意味着该函数不会使用该指针更改任何值。(当然,除非该函数使用强制转换(const_castC++ 中的 a)。或者,在 C++ 中,指针指向声明的字段mutable。)

Go 有一个非常简单的类型系统。许多语言都有一个复杂的类型系统,您可以通过编写类型来强制执行程序的正确性。在许多情况下,这意味着大量的编程涉及编写类型声明。Go 采取了不同的方法:您的大部分编程都涉及编写代码,而不是类型。您通过编写正确的代码来编写正确的代码,而不是通过编写类型来捕捉您编写不正确代码的情况。如果您想捕获不正确的代码,您可以编写分析器,就像go vet在您的代码中查找无效的情况一样。为 Go 编写这些类型的分析器比为 C/C++ 编写要容易得多,因为语言更简单。

这种方法有优点也有缺点。Go 在这里做出了明确的选择:编写代码,而不是类型。这不是每个人的正确选择。


查看完整回答
反对 回复 2021-11-22
  • 2 回答
  • 0 关注
  • 198 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信