【问题标题】:What are "first-class" objects?什么是“一流”对象?
【发布时间】:2010-09-19 16:48:07
【问题描述】:

什么时候对象或其他东西在给定的编程语言中被称为“一流的”,为什么?它们与没有它们的语言有何不同?

当人们说“一切都是对象”时(就像在 Python 中一样),他们真的是指“一切都是一流的”吗?

【问题讨论】:

    标签: python language-agnostic


    【解决方案1】:

    简而言之,这意味着对对象的使用没有任何限制。这是一样的 任何其他对象。

    第一类对象是一个实体,可以动态创建、销毁、传递给函数、作为值返回,并拥有编程语言中其他变量所拥有的所有权利。

    根据语言,这可以 暗示:

    • 可表示为匿名文字值
    • 可存储在变量中
    • 可存储在数据结构中
    • 具有内在身份(独立于任何给定名称)
    • 在平等方面与其他实体具有可比性
    • 可作为参数传递给过程/函数
    • 作为过程/函数的结果可返回
    • 在运行时可构造
    • 可打印
    • 可读性
    • 可在分布式进程之间传输
    • 可存储在正在运行的进程之外

    Source.

    然而,在 C++ 中,函数本身并不是一流的对象:

    • 您可以覆盖“()”运算符,从而可以拥有一个对象函数,这是一等的。
    • 函数指针是第一类的。
    • boost bind、lambda 和 function 确实提供一流的功能

    在 C++ 中,类不是第一类对象,而是这些类的实例。在 Python 中,类 对象都是第一类对象。 (有关作为对象的类的更多详细信息,请参阅this answer

    这里是 Javascript 一等函数的例子:

    // f: function that takes a number and returns a number
    // deltaX: small positive number
    // returns a function that is an approximate derivative of f
    function makeDerivative( f, deltaX )
    {
        var deriv = function(x)
        { 
           return ( f(x + deltaX) - f(x) )/ deltaX;
        }
        return deriv;
    }
    var cos = makeDerivative( Math.sin, 0.000001);
    // cos(0)     ~> 1
    // cos(pi/2)  ~> 0
    

    Source.

    不是第一类对象的实体称为第二类对象。 C++ 中的函数是二等的,因为它们不能被动态创建。

    关于编辑:

    编辑。当一个人说“一切都是 一个对象”(就像在 Python 中一样),他是 确实意味着“一切都是 一流”?

    “对象”一词可以随意使用,并不意味着是一流的。将整个概念称为“一流实体”可能更有意义。但在 Python 中,他们的目标是让一切都成为一流的。我相信发表你的言论的人的意图是一流的。

    【讨论】:

    • 你能举一些不是“头等舱”的对象的例子吗?
    • @SudipBhandari 我也想知道同样的事情,最后偶然发现了关于这个主题的有用的维基百科文章:first-class citizen/object。我发现 Robin Popplestone 的定义特别有用。 (顺便说一句,发布一篇 WP 文章可能看起来非常明显,但我没有意识到这是一个基本的编程语言概念)
    • 有人可以举一个匿名文字值的例子吗?
    • @Papaya-Automaton:当然,几乎所有的原始类型:整数、字符串、浮点数、布尔常量“true”和“false”。根据语言的不同,您可能有更多(例如,C 中的数组 [1,2,3],或 Scheme 中的列表 '(1 2 3))。
    【解决方案2】:

    “当一个人说“一切都是对象”(就像在 Python 中一样)时,他的意思真的是“一切都是一流的”吗?”

    是的。

    Python 中的一切都是正确的对象。甚至是其他语言中的“原始类型”。

    你会发现像2 这样的对象实际上有一个相当丰富和复杂的接口。

    >>> dir(2)
    ['__abs__', '__add__', '__and__', '__class__', '__cmp__', '__coerce__', '__delattr__', '__div__', '__divmod__', '__doc__', '__float__', '__floordiv__', '__getattribute__', '__getnewargs__', '__hash__', '__hex__', '__index__', '__init__', '__int__', '__invert__', '__long__', '__lshift__', '__mod__', '__mul__', '__neg__', '__new__', '__nonzero__', '__oct__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__str__', '__sub__', '__truediv__', '__xor__']
    

    因为一切都是 Python 中的一等对象,所以比较少见的特殊情况。

    例如,在 Java 中,有些原始类型(int、bool、double、char)不是正确的对象。这就是为什么 Java 必须引入 Integer、Boolean、Double 和 Character 作为一等类型。这很难教给初学者——为什么原始类型和类必须并排存在并不明显。

    这也意味着一个对象的类——它本身——一个对象。这与 C++ 不同,在 C++ 中,类在运行时并不总是有不同的存在。

    2 的类型是type 'int' 对象,它有方法、属性和类型。

    >>> type(2)
    <class 'int'>
    

    int 这样的内置类型的类型是type 'type' 对象。这也有方法和属性。

    >>> type(type(2))
    <class 'type'>
    

    【讨论】:

    • 现代 Python 也是如此。在旧的 Python(版本 1?在我之前)中,你不能从 int 继承。因此,“旧”与“新式类”(在 3 中,不再有旧式类)。
    • 这在现代 python 中甚至都不是真的。忽略为什么这会很有用,所有按位/布尔运算符都不是一流的对象。试试dir(&amp;)。仍然有一些语言语法不能分配给变量,也不能用作第一类对象。
    【解决方案3】:

    “头等舱”意味着您可以按照通常的方式对它们进行操作。大多数情况下,这只是意味着您可以将这些一等公民作为参数传递给函数,或者从函数中返回它们。

    这对于对象是不言而喻的,但对于函数甚至类来说并不总是那么明显:

    void f(int n) { return n * 2; }
    
    void g(Action<int> a, int n) { return a(n); }
    
    // Now call g and pass f:
    
    g(f, 10); // = 20
    

    这是 C# 中的一个示例,其中函数实际上 不是 一等对象。因此,上面的代码使用了一个小的解决方法(即称为Action&lt;&gt; 的通用委托)将函数作为参数传递。其他语言,例如 Ruby 或 Python,甚至允许将类和代码块视为普通变量(或者在 Ruby 的情况下为常量)。

    【讨论】:

      【解决方案4】:

      来自Structure and Interpretation of Computer Programs 中的幻灯片,第 2A 课(1986 年),其中依次引用了Christopher Stracey

      一等公民的权利和特权:

      • 由变量命名。
      • 作为参数传递给过程。
      • 作为过程值返回。
      • 要合并到数据结构中

      【讨论】:

        【解决方案5】:

        IMO 这是用于用自然语言描述事物的隐喻之一。该术语本质上是在将函数描述为第一类对象的上下文中使用的。

        如果您考虑面向对象的语言,我们可以为对象赋予各种特性,例如:继承、类定义、传递给其他代码部分的能力(方法参数)、存储在数据结构中的能力等。如果我们可以对通常不被视为对象的实体执行相同操作,例如 java 脚本中的函数,此类实体被视为第一类对象。

        这里的第一类本质上是指,不作为第二类处理(行为退化)。从本质上讲,嘲笑是完美的或无法区分的。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-06-29
          • 2018-01-26
          • 1970-01-01
          • 2017-08-15
          • 2011-06-12
          相关资源
          最近更新 更多