什么是“第一类”对象?
在某种编程语言中,当我们说某些东西是“第一类”的时候,这是什么意思呢?为什么会这样说?它们和那些不是第一类的语言有什么不同呢?
当有人说“万物皆对象”(比如在Python中),这是不是意味着“万物都是第一类的”呢?
6 个回答
“一等公民”这个说法的意思是你可以像平常一样对待它们。大多数情况下,这意味着你可以把这些一等公民当作参数传递给函数,或者从函数中返回它们。
对于对象来说,这一点很明显,但对于函数甚至类来说,就不一定那么明显了:
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<>
的泛型委托)来把函数当作参数传递。其他一些语言,比如Ruby或Python,允许把类和代码块也当作普通变量来处理(在Ruby中,甚至可以把它们当作常量)。
当有人说“在Python中一切都是对象”时,他的意思是“一切都是一等公民”吗?
没错。
在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'>
简单来说,这意味着对这个对象的使用没有限制。它和其他任何对象都是一样的。
所谓的“第一类对象”,就是一种可以动态创建、销毁、传递给函数、作为返回值的实体,并且在编程语言中享有和其他变量一样的权利。
根据不同的编程语言,这可能意味着:
- 可以用匿名的字面值表示
- 可以存储在变量中
- 可以存储在数据结构中
- 有独立的身份(不依赖于任何特定的名称)
- 可以和其他实体进行相等比较
- 可以作为参数传递给过程/函数
- 可以作为过程/函数的结果返回
- 可以在运行时构造
- 可以被打印
- 可以被读取
- 可以在分布式进程之间传输
- 可以存储在运行进程之外
来源。
在C++中,函数本身不是第一类对象,但:
- 你可以重载'()'操作符,这样就可以有一个对象函数,它是第一类的。
- 函数指针是第一类对象。
- boost bind、lambda和function都提供第一类函数。
在C++中,类不是第一类对象,但这些类的实例是。而在Python中,类和对象都是第一类对象。(想了解更多关于类作为对象的内容,可以查看这个回答)。
下面是一个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
来源。
那些不是第一类对象的实体被称为第二类对象。在C++中,函数是第二类对象,因为它们不能动态创建。
关于编辑:
编辑。当有人说“所有东西都是对象”(比如在Python中),他是否真的意味着“所有东西都是第一类的”?
这个“对象”一词可以宽泛使用,并不一定意味着是第一类对象。可能更合理的说法是把整个概念称为“第一类实体”。但在Python中,他们确实希望让所有东西都是第一类的。我相信说这句话的人是想表达第一类的意思。