鸭子类型与旧的“变体”类型和/或接口有何不同?

2023-12-20

我经常看到“鸭子打字”这个短语,甚至还遇到过一两个代码示例。我太忙于做自己的研究,有人可以简单地告诉我:

  • “鸭子型”和老式“变体型”之间的区别,以及
  • 提供一个示例,说明我可能更喜欢鸭子类型而不是变体类型,并且
  • 提供一个我想要的例子have使用鸭子打字来完成?

我并不是想通过怀疑这个“新”结构的力量来显得愚蠢,我也不是通过拒绝进行研究来回避这个问题,但我对我所看到的所有蜂拥而至的炒作感到嘎嘎叫最近它。看起来像no对我来说打字(又名动态打字),所以我没有立即看到它的优点。

附录:感谢到目前为止提供的示例。在我看来,使用像“O->can(Blah)”这样的东西相当于进行反射查找(这可能并不便宜),和/或与编译器可能会说的(O是IBlah)大致相同能够为您检查,但后者的优点是可以区分我的 IBlah 界面和您的 IBlah 界面,而其他两个则不然。诚然,每个方法都有很多微小的接口会变得混乱,但同样可以检查很多单独的方法......

...所以我又不明白了。它是一个非常好的节省时间的工具,还是同样的旧东西装在一个全新的袋子里?哪里有这样的例子requires鸭子打字?


在此处的一些答案中,我看到了一些术语的错误使用,这导致人们提供错误的答案。

因此,在给出答案之前,我将提供一些定义:

  1. 强类型

    如果一种语言强制执行程序的类型安全,则该语言是强类型的。这意味着它保证了两件事:一种叫做进步的东西,另一种叫做保存的东西。进步基本上意味着所有“有效类型”的程序实际上都可以由计算机运行,它们可能会崩溃,或抛出异常,或运行无限循环,但它们实际上可以运行。保留意味着如果一个程序是“有效类型的”,那么它将始终是“有效类型的”,并且没有变量(或内存位置)将包含不符合其指定类型的值。

    大多数语言都具有“进度”属性。然而,有许多不满足“保存”属性。 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++ 是强类型的,这是不可能的。如果您尝试将字符数组转换为“foo”实例,类型安全语言(例如 C#、Java、VB、lisp、ruby、python 等)将引发异常。

  2. 弱类型

    如果某些东西不是强类型的,那么它就是弱类型的。

  3. 静态类型

    如果一种语言的类型系统在编译时得到验证,则该语言是静态类型的。静态类型语言可以是“弱类型”(如 C),也可以是强类型(如 C#)。

  4. 动态类型

    动态类型语言是一种在运行时验证类型的语言。许多语言在某种程度上混合了静态类型和动态类型。例如,C# 将在运行时动态验证许多强制转换,因为无法在编译时检查它们。其他示例包括 Java、VB 和 Objective-C 等语言。

    还有一些语言“完全”或“大部分”是动态类型的,例如“lisp”、“ruby”和“small talk”

  5. 鸭子打字

    鸭子类型与静态、动态、弱或强类型完全正交。这是编写可以与对象一起使用的代码的实践,无论其底层类型标识如何。例如,以下 VB.NET 代码:

    function Foo(x as object) as object
        return x.Quack()
    end function
    

    无论传递到“Foo”的对象是什么类型,只要定义了一个名为“Quack”的方法,都可以工作。也就是说,如果该物体看起来像鸭子,走路像鸭子,说话像鸭子,那么它就是鸭子。鸭子打字有多种形式。可以有静态鸭子类型、动态鸭子类型、强鸭子类型和弱鸭子类型。 C++ 模板函数是“弱静态鸭子类型”的一个很好的例子。 “JaredPar”帖子中显示的示例显示了“强静态鸭子类型”的示例。 VB 中的后期绑定(或者 Ruby 或 Python 中的代码)可实现“强动态鸭子类型”。

  6. Variant

    变体是一种动态类型的数据结构,可以保存一系列预定义的数据类型,包括字符串、整数类型、日期和 com 对象。然后,它定义了一系列用于分配、转换和操作存储在变体中的数据的操作。变体是否是强类型取决于它所使用的语言。例如,VB 6 程序中的变体是强类型的。 VB 运行时确保用 VB 代码编写的操作符合变体的类型规则。通过 VB 中的变体类型将字符串添加到 IUnknown 将导致运行时错误。然而,在 C++ 中,变体是弱类型的,因为所有 C++ 类型都是弱类型的。

好的......现在我已经弄清楚了定义,我现在可以回答你的问题:

VB 6 中的一个变体支持一种形式的鸭子类型。与变体相比,有更好的方法进行鸭子类型(Jared Par 的示例是最好的示例之一),但您可以使用变体进行鸭子类型。也就是说,您可以编写一段代码来对对象进行操作,而不管其底层类型标识如何。

然而,使用变体来做这件事并不能真正提供很多验证。静态类型的鸭子类型机制(如 JaredPar 描述的那样)提供了鸭子类型的好处,以及编译器的一些额外验证。这真的很有帮助。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

鸭子类型与旧的“变体”类型和/或接口有何不同? 的相关文章

  • 带有 std::variant 或 union 包装器的通用接口

    这个问题与使用 std variant 强制使用通用接口 无需继承 https stackoverflow com questions 72434897 enforcing a common interface with stdvarian
  • 避免实现接口中存在的方法 - java

    我有一个如下所示的界面 public interface a public void m1 public void m2 public void m3 public class A implements a public void m3 i
  • Moq-ing 类或接口有什么区别?

    我一直在使用moq http code google com p moq 在我的单元测试中模拟对象 我在关于最小起订量的网站上看到它能够模拟类和接口 有一天 我与我的一位同事进行了讨论 他们表示没有理由模拟类 我应该只模拟接口 我对此并没有
  • 通用接口列表

    如果我有一个带有几个实现类的通用接口 例如 public interface IDataElement
  • CUDD C++ 接口,用于将布尔值转换为 BDD 以及生成的最小项集(到割集)

    我正在与 https github com ivmai cudd https github com ivmai cudd 目标是进行以下重复过程 1 输入 连贯 非递减 布尔函数表达式 顶部 a 1a 2a 3 x 1x 2x 3 z 1z
  • C# 接口实现关系只是“Can-Do”关系?

    今天有人告诉我 C 中的接口实现只是 Can Do 关系 而不是 Is A 关系 这与我长期以来所相信的LSP 里氏替换原理 相冲突 我一直认为所有的继承都应该意味着 Is A 关系 所以 如果接口实现只是一种 Can Do 关系 如果有一
  • 有没有办法找到哪些 .NET 类实现了某个接口?

    例如 如果我想查看我的 NET 选项用于实现 IList 或 IDictionary 有没有办法找到它 例如在 MSDN 文档中 我认为可以使用反射器 http www red gate com products reflector
  • 界面与组合

    我想我理解接口和抽象之间的区别 抽象设置默认行为 在纯抽象的情况下 行为需要由派生类设置 接口是您所需要的 无需基类的开销 那么接口相对于组合的优势是什么 我能想到的唯一优点是在基类中使用受保护的字段 我缺少什么 你的标题没有意义 你的解释
  • 是否可以使用显式实现的接口属性对类进行 json 序列化?

    interface A string Name get set interface B string Name get set class C A B string A Name get set string B Name get set
  • Android proguard Javascript 接口问题

    我的项目在使用 proguard 进行混淆后因 javascriptinterface 失败 这是包含混淆器配置的一些建议的链接 但它在我的情况下不起作用 http groups google com group android devel
  • Auto-value-gson出现接口错误,注册一个InstanceCreator?

    我有一个如下所示的接口类 public interface Species String name And a Human实现的类 AutoValue使用类型适配器 AutoValue public abstract class Human
  • Java中接口作为方法参数

    前几天去面试 被问到了这样的问题 问 反转链表 给出以下代码 public class ReverseList interface NodeList int getItem NodeList nextNode void reverse No
  • C# 中的接口继承

    我试图解决我在编写应用程序时遇到的相当大的 对我来说 问题 请看这个 为了简单起见 我将尝试缩短代码 我有一个名为的根接口IRepository
  • SWI-Prolog 中的跨模块“接口”调用

    这可能是 SWI Prolog 模块系统特有的 假设我们有三个 Prolog 模块 在 SWI Prolog 模块系统中 robin 在文件中robin pl arthur 在文件中arthur pl helper 在文件中helper p
  • 在 Delphi 中将对象转换为 OleVariant

    有没有办法在 OleVariant 中传递包装并解开 TObject 后代 我正在尝试跨自动化对象传递 TObject 我知道这不是一个好主意 但我没有更好的选择 该对象将在来自同一自动化 dll 的对象之间传递 如果这有什么区别的话 像这
  • C++ 用纯虚方法重写纯虚方法

    用另一个纯虚拟方法覆盖一个纯虚拟方法是否有意义 是否存在任何功能差异或代码风格原因使您更喜欢以下选项之一而不是另一个 class Interface public virtual int method 0 class Abstract pu
  • 如何在应用程序目录层次结构中构建接口?

    将它们全部放在一个单独的文件夹结构中还是与实现它们的类一起放置 切勿将接口与实现它们的类放在一起 除非这些类满足以下要求 这样做将引入一个紧耦合在接口和实现者之间 如果不同时引用实现者 您将无法创建该接口的其他实现 你基本上有两个选择 将接
  • 是否可以通过引用以基类作为参数的函数来传递派生类

    假设我们有一个抽象基类IBase使用纯虚方法 接口 然后我们推导出CFoo CFoo2来自基类 我们有一个知道如何使用 IBase 的函数 Foo IBase input 这些情况下通常的场景是这样的 IBase ptr static ca
  • 点击界面没有出现

    我决定添加一个点击界面并在我的代码中使用它 但我能够得到它的状态 sudo ip f link tuntap add tap10 mode tap sudo ip link set tap10 up 之后当我执行 ip link 时 tap
  • C# 如何在运行时动态生成实现不同接口的对象?

    我正在研究如何解决问题 但我什至不确定这在 C 和 NET 3 5 中是否可行 假设我的接口数量有限 每个接口都描述一组特定的 不相关的方法 现在我有许多现实世界的设备 每个设备都可以仅实现这些接口的一个子集 在与这些设备建立通信期间 他们

随机推荐