为什么像Java这样的语言区分字符串和char而其他语言不区分?

时间:2013-02-21 19:10:12

标签: java python ruby string char

我注意到像Java这样的语言有一个char原语和一个字符串类。其他语言如Python和Ruby只有一个字符串类。这些语言使用长度为1的字符串来表示字符。

我想知道这种区别是否是由于历史原因。我理解直接影响Java的语言有char类型,但没有字符串。而是使用char *或char []形成字符串。

但我不确定是否有这样做的实际目的。我也很好奇,如果某种方式在某些情况下优于另一种方式。

为什么像Java这样的语言区分char原语和字符串类,而像Ruby和Python这样的语言呢?

当然必须有某种设计方面的关注,无论是惯例,效率,清晰度,易于实现等等。语言设计师真的只是从帽子中选择一个角色表示,可以这么说吗?

5 个答案:

答案 0 :(得分:4)

底线就是语言设计师决定如何做到这一点。很难比这更进一步。

然而,关于C的一点,通常被认为是较低级别的语言,因为语法更准确地反映了正在执行的数据和任务的性质。将字符作为字符串处理将是一个与C不同的抽象级别。这将使得不太清楚封底下的数据是什么样的。当你需要的只是一个角色时,它几乎肯定会增加开销。

请注意,C型语言确实支持单个字符串,因此我认为你真的可以充分利用这两个世界。

答案 1 :(得分:4)

编辑1 添加了许多来源链接;改进了Lisp的历史故事;回答为什么Java有灵长类动物。 编辑2 评论现代脚本语言,解释效率如何不再是一个问题

回到过去,内存很昂贵 - 即使是简单的计算机也只有几千字节。您必须同意的典型服务条款将超过整个系统的RAM。这意味着数据结构必须非常远小于您今天可以设计的数据结构。

计算机于20世纪40年代在英国和美国启动,这些工程师所需的最小字符集是西欧字母表,没有任何激动人心的口音。 0-9,A-Z和a-z是62个字符。添加31个控制字符,空格和一些标点符号,您可以将所有这些设置为7位。适合电传打字机。

现在,这些7位可以在不同的架构上以不同的方式布局。如果您使用IBM,则必须知道EBCDICASCII完全不同。

&#39> 60s和F 70s的语言反映了这些问题,并将字符串打包到尽可能小的空间中:

  • Pascal:一个打包的字节数组 - 固定长度而不是以空值终止
  • C:以空值结尾的字节序列(通常被认为是一个数组,使用的是数组下标简直就是pointer arithmetic的疯狂黑客的想法)
  • Fortran 66:Strings?你不需要它们。将字符存储在整数中并使用READ,WRITE和FORMAT

作为这些语言的程序员,我可以说这很糟糕。特别是因为大多数商业程序需要大量的文本输入和操作。随着内存变得越来越便宜,程序员倾向于在其他任何东西之前编写字符串实用程序,以便能够做任何有效的事情。

固定长度的字符串(例如Pascal)是有效的,但如果你需要扩展或收缩它们甚至是单个字符,那就太尴尬了。

C的空终止方法的缺点是长度不与字符串一起存储,因此覆盖缓冲区并使应用程序崩溃非常容易。此类错误仍然是计算机不安全的主要原因。有两种方法可以解决这个问题:

  • 每次写入时检查字符串长度:这意味着扫描内存直到找到空字符。丑
  • malloc新内存并将字符串复制到新内存中,然后free

80年代,标准库越来越多地被用于处理字符串 - 这些是由工具供应商和操作系统提供商提供的。有标准化的重大举措,但各方互相斗争,以控制标准,这是丑陋的。

国际化程度的提高也带来了另一个问题 - 国际字符集。首先,对于不同的欧洲语言(口音,希腊语,西里尔语),ASCII被扩展为8位ISO 8859-1,然后Unicode完全将计算机带到了世界的各个角落。这带来了UTF-8UTF-16等字符编码问题以及如何在这些不同方法之间进行转换。

我还应该注意Lisp引入了垃圾收集。这解决了C malloc / free的复杂性。 Lisp强大的数组和序列库可以自然地用于字符串。

将这些趋势结合在一起的第一个主要流行语言是Java。它结合了语言中的三个改进

  1. 国际化和Unicode:独特的数据类型Character和原始char
  2. 封装:固定长度与空终止的问题可以通过以下方式解决:
    1. 不可改变
    2. VM和GC中的聪明优化
  3. 库:所有基本字符串操作功能都在语言中标准化。
  4. 现在有些语言中的每个值都是一个对象。然而,当Java在90年代后期构思出来时,GC和JIT / Hotspot技术远没有它们现在那么快(至少部分是因为RAM限制,但算法也有所改进)。 Gosling was concerned about performance并保留原始数据类型。

    另一点:在Java中,自然存在一个Character类 - 它是许多操作和实用方法的自然之家,例如isWhiteSpace()isLetter()有点复杂的日语,韩语和印度语。

    Python创建了一个poor early decision来将字符定义为8位ASCII;你可以通过首先引入另一种微妙的不同且不兼容的数据类型(unicode)来看到随之而来的问题,现在只能通过复杂的迁移到Python 3.x来解决。

    现代语言(包括脚本语言)遵循关于字符串库应如何看起来的广泛共识,如Java和Python所示。

    每种语言都是为特定目的而设计的,因此可以通过不同方式平衡竞争性设计问题。在过去的60年里,现代语言的优势在于性能和内存的巨大改进,因此他们可以优先考虑泛化,纯度和实用性而不是CPU和RAM的效率。这对脚本语言来说是明确的,因为脚本编写的语言已经做出了这个决定。因此,现代语言往往只有高级字符串类型。

    TL / DR 早期的计算机内存受到惊人的限制,迫使最简单的实现。现代语言受益于GC识别国际化(8位 - > 16位)字符并封装字符串数据类型以使字符串操作安全且容易。

答案 2 :(得分:2)

现在,我对这个问题的看法可能会以某种形式反映出这里的一些答案,但无论如何我会说:

是的,(和其他人一样)像C这样的低级语言将优化,性能和机器级别的细节考虑在内,远远超过Perl,Ruby或Python等脚本语言。现在,这种“完全控制”心态的结果是,与脚本语言相比,您通常需要担心更多的事情。

那么我想说什么呢?好吧,SO的成员曾经把“Zen of Python”传给我,只有该文档中的一些摘录包含了一些核心的Python哲学,如“可读性计数”,“简单比复杂更好”,以及"There should be one-- and preferably only one --obvious way to do it.我强调最后一次提取是有原因的。

继续,这里是一个抽象编程语言的例子, 有一个char类型:SML。举个例子,我在交互模式下做了两个语句:

- val a = "a"
val a = "a" : string    #interpreter type feedback

- val a = #"a"
val a = #"a" : char     #interpreter type feedback

在上面两个例子中,我有两种表示一个人类可读字符的方法,尽管它们是根本不同的类型。尽管按照今天的标准,SML是一种相对抽象的语言,但它的核心哲学在于计算,数学表达语法和bug安全。最后一点更纯粹是功能性语言(SML不纯粹)的情况。因此,虽然抽象提出了一种远离低级语言可怕细节的观点,但它仍然没有像Python这样的语言那样强调像“可读性”和“易用性”这样的概念。 p>

事实上,脚本语言通常强调快速生成代码,以及易于学习和使用的语法。就Ruby来说,松本自己甚至宣称这种语言应该“使用起来很有趣”。基本上,在我最简陋的估计中,我认为不区分Python等语言中的char和字符串数据类型的原因包含在简单性的概念中。详细程度和卷积似乎是脚本语言的敌人。此外,作为最后一点,如果有人倾向于使用C兼容的数据类型,那么Python就有ctypes库。

答案 3 :(得分:1)

  

我不确定这种区别是否是因为历史原因   原因(C只有字符,字符串是用char *或char []形成的)或   如果有这样做的实际目的。我也很好奇   如果某种方式在某些情况下优于另一种方式。

C中,“字符串”的概念是由结束字符\0终止的字符数组/字符系列。否则,“string”就像C中的任何其他数组一样。

例如C#和其他几种语言将字符串视为抽象,字符串更像是一个不透明的对象。该对象包含处理字符串的方法,但字符串存储的确切方式是“隐藏”给程序员。

原因是C语言比较旧的语言更老,而且比新语言更接近硬件。

如何在一种语言中定义字符串(无论是使用单引号还是使用dobuble引号)实际上只是设计语言的人当时认为是好事的实现细节。

答案 4 :(得分:1)

在C和C ++中,char只是一个“小”整数。虽然它的名称建议用于字符编码,但它在桌面系统上至少使用Unicode或任何需要支持各种语言和字母表的系统时,其用途正在逐渐减少。然而,因为这些是能够直接访问硬件的“系统级”语言,所以还必须具有能够寻址特定体系结构上的最小可寻址存储器单元的数据类型。这就是char是必要的原因。

C#区分用于字符编码的类型char(实际上是16位)和8位的最小可寻址单元类型byte。这种清晰度可能是后来参加聚会的好处。

当然,C根本没有字符串数据类型,它只有一个nul终止字符数组的约定和一个使用该约定的函数库(顺便提一下,这是一个简单但效率低下的约定{ {3}})。在C ++中,字符串类带来了真正的字符串类型的优点,并且可以避免一些低效率和危险 - 尽管减轻危险会增加其自身不同的性能损失。)