Alb*_*ert 17 c++ python java string immutability
我想知道从程序员的角度来看,字符串类型是不可变的好处.
技术优势(在编译器/语言方面)可以概括为,如果类型是不可变的,则更容易进行优化.请阅读此处了解相关问题.
另外,在一个可变的字符串类型中,要么你已经内置了线程安全(然后再次,优化更难),或者你必须自己做.在任何情况下,您都可以选择使用具有内置线程安全性的可变字符串类型,因此这不是不可变字符串类型的优势.(同样,更容易进行处理和优化以确保不可变类型的线程安全,但这不是重点.)
但是不可变字符串类型在使用中有什么好处?让某些类型不可变而其他类型不可变的重点是什么?这对我来说似乎很不一致.
在C++中,如果我想要一些字符串是不可变的,我将它作为const引用传递给function(const std::string&).如果我想要一个原始字符串的可更改副本,我将其作为传递std::string.只有当我想让它变得可变时,我才将它作为reference(std::string&)传递.所以我只能选择我想做的事情.我可以用各种可能的类型做到这一点.
在Python或Java中,某些类型是不可变的(大多数都是基本类型和字符串),而其他类型则不是.
在像Haskell这样的纯函数式语言中,一切都是不可变的.
是否有充分理由说明这种不一致是否有意义?或者仅仅是出于技术上的低级原因?
Ale*_*lli 16
让某些类型不可变而其他类型不可变的重点是什么?
如果没有一些可变类型,你就必须全力以赴地进行纯函数式编程 - 一种完全不同的范式,而不是目前最流行的OOP和程序方法,虽然功能非常强大,但显然对很多程序员来说都是非常具有挑战性的. (当你确实需要一种没有任何可变性的语言的副作用时会发生什么,当然你不可避免地要进行实际编程,这是挑战的一部分 - 例如,Haskell的Monads是一种非常优雅的方法,但有多少程序员你是否知道完全自信地理解它们并且可以使用它们以及典型的OOP结构? - ).
如果你不理解拥有多种范式的巨大价值(FP一和一关键依赖于可变数据),我建议研究Haridi和Van Roy的杰作,概念,技术和计算机编程模型 - "一个SICP对于21世纪",正如我曾经描述的那样;-).
大多数程序员,无论是否熟悉Haridi和Van Roy,都会轻易承认至少拥有一些可变数据类型对他们很重要.尽管我从你的Q中引用了上述句子,它采用了完全不同的观点,但我相信这也可能是你困惑的根源:不是 "为什么有些人",而是"为什么有些不可改变的".
在Fortran实现中曾经(意外地)获得了"彻底可变"的方法.如果你有,比方说,
  SUBROUTINE ZAP(I)
  I = 0
  RETURN
然后一个程序片段,例如,
  PRINT 23
  ZAP(23)
  PRINT 23
将打印23,然后0 - 数字23已经变异,所以在程序的其余部分中对23的所有引用实际上都指的是0.编译器中没有错误,技术上:Fortran对程序有什么细微的规则是和不允许将常量vs变量传递给分配给它们的参数的过程,并且这个片段违反了那些鲜为人知的,非编译器可执行的规则,因此它只是在程序中,而不是在编译器中.实际上,当然,这种方式导致的错误数量高得令人无法接受,因此在这种情况下,典型的编译器很快就会切换到破坏性较小的行为(如果操作系统支持,则将常量放在只读段中以获得运行时错误;或者,传递一份新的副本虽然有开销,但是常数而不是常数本身; 等等)尽管技术上它们是程序错误,允许编译器非常"正确"地显示未定义的行为;-).
在其他一些语言中强制执行的替代方法是添加多种参数传递方式的复杂性 - 最明显的可能是在C++中,使用按值,按引用,通过常量引用,通过指针,通过常量指针,......然后当然你会看到程序员被声明所困惑(例如,如果是某个函数的参数,const foo* const bar最右边const基本上是无关紧要的bar......但是如果bar是局部变量则是至关重要的......! - ).
实际上Algol-68可能沿着这个方向走得更远(如果你有一个值和一个参考,为什么不参考参考?或参考参考?&c  -  Algol 68对此没有限制,规则定义正在发生的事情可能是"用于实际用途"编程语言中发现的最微妙,最难的混合.早期的C(只有按值和明确的指针 - 没有const,没有参考,没有并发症)无疑是对它的反应,就像最初的Pascal一样.但const很快就悄悄进入,并发症再次开始增加.
Java和Python(以及其他语言)通过强大的简单砍刀切入这个丛林:所有参数传递和所有赋值都是"通过对象引用"(从不引用变量或其他引用,从不引用语义隐式副本,&c) .将(至少)数字定义为语义不可变通过避免诸如上面的Fortran代码所展示的"oopses"来保持程序员的理智(以及语言简单性的这一宝贵方面).
处理字符串作为原语,就像数字是与语言意高语义层面相当一致,因为在现实生活中,我们也需要是一样简单的数字,使用字符串; 诸如将字符串定义为字符列表(Haskell)或作为字符数组(C)的替代方案对编译器(在这种语义下保持有效性能)和程序员(有效地忽略这种任意结构以使字符串的使用变得简单)提出了挑战原始,正如现实生活中的编程经常需要的那样).
Python进一步增加了一个简单的不可变容器(tuple)并将散列与"有效不变性" 捆绑在一起(这避免了程序员遇到的某些意外,例如,在Perl中,其哈希允许可变字符串作为键) - 和为什么不?一旦你有了不变性(一个珍贵的概念,拯救程序员不必学习N个不同的语义,用于赋值和参数传递,N趋于随着时间的推移而增加;-),你也可以从中获得全部里程数;-) .