鸭子打字,它必须是动态的吗?

cdi*_*ins 24 type-systems duck-typing language-design definitions structural-typing

维基百科曾经说*关于鸭子打字:

在使用面向对象编程语言的计算机编程中,duck typing是一种动态类型,其中对象的当前方法和属性集确定有效语义,而不是从特定类或特定接口的实现继承.

(*Ed.注意:自从发布此问题以来,维基百科文章已经过编辑,删除了"动态"一词.)

它说关于结构类型:

结构类型系统(或基于属性的类型系统)是类型系统的主要类,其中类型兼容性和等价性由类型的结构决定,而不是通过显式声明.

它将结构子类型与鸭子类型进行对比,如下所示:

[结构系统]与... duck typing相反,其中仅检查在运行时访问的结构的一部分的兼容性.

然而,术语鸭子打字在我看来至少是直观地包含结构子打字系统.实际上维基百科说:

这个概念的名称[鸭子打字]是指鸭子测试,归功于James Whitcomb Riley,其措辞可能如下:"当我看到一只鸟像鸭子一样散步,像鸭子一样游动,像鸭子一样呱呱叫,我称这只鸟为鸭子."

所以我的问题是:为什么我不能将结构子类型称为鸭子打字?是否存在动态类型语言,这些语言也不能被归类为鸭子类型?

后记:

正如有人叫daydreamdrunk上reddit.com如此雄辩地提出,它 "如果它编译像鸭子,像鸭子链接..."

后后记

许多答案似乎基本上只是重复我已经在这里引用的内容,而没有解决更深层次的问题,这就是为什么不使用术语duck-typing来涵盖动态类型和结构子类型?如果您只想谈论鸭子类型而不是结构子类型,那么只需调用它:动态成员查找.我的问题是没有关于鸭子打字这个术语对我说,这只适用于动态语言.

dsi*_*cha 26

C++和D模板是鸭子打字的一个完美的例子,它不是动态的.绝对是:

键入一个对象的当前方法和属性集确定有效语义,而不是从特定类或特定接口的实现继承.

您没有显式指定类型必须继承的接口来实例化模板.它只需要具有模板定义中使用的所有功能.但是,一切都在编译时得到解决,并编译成原始的,不可思议的十六进制数字.我称之为"编译时鸭子打字".我已经从这种心态编写了整个库,隐式模板实例化是编译时鸭子打字,并认为它是最不被重视的功能之一.


Wes*_*ley 14

结构类型系统

结构类型系统将一个完整类型与另一个完整类型进行比较,以确定它们是否兼容.对于两种类型A并且B兼容,A并且B必须具有相同的结构 - 也就是说,on 和on上的每个方法必须具有相同的签名.AB

鸭子打字

鸭子打字认为两种类型对于手头的任务是等效的,如果他们都可以处理该任务.对于两种类型A并且B等同于想要写入文件的一段代码,A并且B两者都必须实现write方法.

摘要

结构类型系统比较每个方法签名(整个结构).Duck输入比较与特定任务相关的方法(与任务相关的结构).

  • 动态类型描述了一些非常微妙的不同.动态类型语言仍然可以强类型化.当然,`foo`变量可以是`Teacher`对象,也可以是`Convict`对象,但在运行时,可以明确知道`foo`的类型.Duck typing描述了对象的_behaviour_.`foo`既可以是`老师',也可以是'罪犯',但只要`foo`可以唱歌(carol)`我就不在乎.动态类型意味着我们在运行时知道对象的类型; 鸭子打字意味着我们只关心一个物体是否能以某种方式行事. (8认同)

Dar*_*rio 10

鸭子打字意味着如果它恰到好处,那就没关系

这适用于动态类型

def foo obj
    obj.quak()
end
Run Code Online (Sandbox Code Playgroud)

或静态类型的编译语言

template <typename T>
void foo(T& obj) {
    obj.quak();
}
Run Code Online (Sandbox Code Playgroud)

关键在于,在两个示例中,没有关于给定类型的任何信息.就在使用时(在运行时或编译时!),检查类型,如果满足所有要求,代码就可以工作.值在声明时没有明确的类型.

结构类型依赖于显式键入您的值,就像通常一样 - 区别在于具体类型不是通过继承来识别,而是通过它的结构来识别.

上面例子的结构类型代码(Scala风格)将是

def foo(obj : { def quak() : Unit }) {
    obj.quak()
}
Run Code Online (Sandbox Code Playgroud)

不要将此与诸如OCaml之类的结构类型语言将其与类型推断相结合,以防止我们明确定义类型.


Mat*_*ank 6

我不确定它是否真的能回答你的问题,但......

模板化的C++代码看起来非常类似于duck-typing,但它是静态的,编译时的,结构化的.

template<typename T>
struct Test
{
    void op(T& t)
    {
        t.set(t.get() + t.alpha() - t.omega(t, t.inverse()));
    }
};
Run Code Online (Sandbox Code Playgroud)


Han*_*Gay 5

我的理解是类型推断器等使用结构类型来确定类型信息(想想Haskell或OCaml),而鸭子类型本身并不关心"类型",只是事物可以处理特定的方法调用/属性访问等(想想respond_to?在Ruby或Javascript中的功能检查).


Sam*_*eff 5

某些编程语言总会有违反某些术语定义的例子.例如,ActionScript支持在技术上不动态的实例上执行鸭子类型样式编程.

var x:Object = new SomeClass();
if ("begin" in x) {
    x.begin();
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我们测试了"x"中的对象实例在调用它之前是否有一个方法"begin"而不是使用接口.这在ActionScript中有效,并且几乎是鸭子类型,即使类SomeClass()本身可能不是动态的.