我一直看到"鸭子打字"这个短语大肆渲染,甚至还遇到了一两个代码示例.我懒得忙着做自己的研究,有人可以简单地告诉我:
'duck type'和old-skool'变体类型'之间的区别,和
提供一个示例,我可能更喜欢鸭子打字而不是变种打字,以及
提供一个我必须使用duck typing来完成的事情的例子?
通过怀疑这种"新"结构的力量,我不是故意要发怒的,而且我不会因为拒绝做研究而避开这个问题,但我正在喋喋不休地谈论我所看到的所有关于这个问题的大肆宣传.最近.它看起来像没有打字(也就是动态打字),所以我没有立即看到优势.
附录:感谢目前为止的例子.在我看来,使用类似'O-> can(Blah)'的东西相当于进行反射查找(可能并不便宜),和/或与编译器可能说的(O是IBlah)大致相同能够检查你,但后者的优点是区分我的IBlah界面和你的IBlah界面,而其他两个没有.当然,对于每种方法都有很多微小的接口会变得混乱,但是那样可以检查很多单独的方法......
...所以我再也没有得到它.在一个全新的麻袋中,它是一个梦幻般的节省时间,还是同样的老东西?需要鸭子打字的例子在哪里?
在这里的一些答案中,我看到一些不正确的术语使用,导致人们提供错误的答案.
所以,在我给出答案之前,我将提供一些定义:
强类型
如果语言强制执行程序的类型安全,则强类型语言.这意味着它保证了两件事:称为进步和其他称为保存的东西.进度基本上意味着所有"有效类型"程序实际上可以由计算机运行,它们可能崩溃,或抛出异常,或运行无限循环,但它们实际上可以运行.保留意味着如果程序被"有效地键入",它将始终是"有效键入",并且没有变量(或内存位置)将包含不符合其指定类型的值.
大多数语言都具有"进步"属性.然而,有许多不满足"保存"属性.一个很好的例子是C++(和C).例如,在C++中可以强制任何内存地址表现得像任何类型一样.这基本上允许程序员随时违反类型系统.这是一个简单的例子:
struct foo { int x; iny y; int z; } char * x = new char[100]; foo * pFoo = (foo *)x; foo aRealFoo; *pFoo = aRealFoo;
此代码允许某人获取一个字符数组并为其编写"foo"实例.如果C++是强类型的,这是不可能的.类型安全的语言,如C#,Java,VB,lisp,ruby,python和许多其他语言,如果你试图将一个字符数组转换为"foo"实例,则会抛出异常.
弱打字
如果没有强类型,则输入的内容很弱.
静态打字
如果在编译时验证其类型系统,则静态类型化语言.静态类型语言可以像C一样"弱类型",也可以像C#一样强类型.
动态输入
动态类型语言是在运行时验证类型的语言.许多语言在静态和动态类型之间都有某种混合.例如,C#将在运行时动态验证多个强制转换,因为在编译时无法检查它们.其他示例是Java,VB和Objective-C等语言.
还有一些语言是"完全"或"大部分"动态类型,如"lisp","ruby"和"small talk"
鸭打字
鸭子打字是与静态,动态,弱或强类型完全正交的东西.编写将与对象一起使用的代码的做法,无论其基础类型标识如何.例如,以下VB.NET代码:
function Foo(x as object) as object return x.Quack() end function
只要定义了一个名为"Quack"的方法,无论传递给"Foo"的对象类型是什么都可以工作.也就是说,如果物体看起来像鸭子,像鸭子一样走路,像鸭子一样说话,那就是鸭子.鸭子打字有多种形式.可以进行静态鸭子打字,动态鸭子打字,强鸭子打字和周鸭打字.C++模板函数是"弱静态鸭子打字"的一个很好的例子."JaredPar"帖子中的示例节目显示了"强静态鸭子打字"的示例.VB中的后期绑定(或Ruby或Python中的代码)实现了"强大的动态鸭子打字".
变种
变体是动态类型的数据结构,可以包含一系列预定义的数据类型,包括字符串,整数类型,日期和com对象.然后,它定义了一系列操作,用于分配,转换和操作变体中存储的数据.变量是否是强类型取决于它的使用语言.例如,VB 6程序中的变体是强类型的.VB运行时确保用VB代码编写的操作符合变体的输入规则.通过VB中的变体类型将字符串添加到IUnknown将导致运行时错误.但是,在C++中,变体是弱类型的,因为所有C++类型都是弱类型的.
好的....现在我已经把定义排除在外了,我现在可以回答你的问题了:
在VB 6中,一种变体可以实现鸭子打字的一种形式.有更好的方法做鸭子打字(Jared Par的例子是最好的),而不是变种,但你可以用变种做鸭子打字.也就是说,您可以编写一段代码来操作对象,而不管其基础类型标识.
但是,使用变体进行此操作并不能真正进行大量验证.一个静态类型的duck类型机制,就像JaredPar描述的那样,给出了duck typing的好处,以及编译器的一些额外验证.这真的很有帮助.
简单的答案是变体是弱类型,而鸭子类型是强类型.
鸭子打字可以很好地总结为"如果它像鸭子一样走路,看起来像鸭子,像鸭子一样,那么它就像鸭子一样." 计算机科学术语认为鸭子是以下界面.
interface IDuck { void Quack(); }
现在让我们来看看Daffy
class Daffy { void Quack() { Console.WriteLine("Thatsssss dispicable!!!!"); } }
在这种情况下,Daffy实际上并不是IDuck.然而它就像鸭子一样.为什么让Daffy实施IDuck,因为很明显Daffy实际上是一只鸭子.
这就是Duck输入的地方.它允许在任何具有IDuck和IDuck引用的所有行为的类型之间进行类型安全转换.
IDuck d = new Daffy(); d.Quack();
Quack方法现在可以在"d"上调用,具有完整的类型安全性.此赋值或方法调用中不存在运行时类型错误的可能性.
鸭子打字只是动态打字或后期绑定的另一个术语.在运行时可能或不实际定义的任何成员访问(例如,obj.Anything)解析/编译的变体对象是鸭子类型.