Interface duck类型与旧类型有何不同;变体';类型和/或接口?

Interface duck类型与旧类型有何不同;变体';类型和/或接口?,interface,variant,duck-typing,Interface,Variant,Duck Typing,我一直看到“ducktyping”这个短语到处流传,甚至遇到一两个代码示例。我懒得忙于自己的研究,有人能简单地告诉我: “duck类型”和旧skool“variant类型”之间的区别,以及 提供一个示例,说明我可能更喜欢duck类型而不是variant类型,以及 提供一个我必须使用duck类型来完成的示例 我并不想因为怀疑这个“新”结构的力量而显得像禽鸟,我也不是因为拒绝做研究而回避这个问题,但我最近看到的关于它的蜂拥而至的炒作让我大吃一惊。在我看来,它似乎没有输入(也称为动态输入),所以

我一直看到“ducktyping”这个短语到处流传,甚至遇到一两个代码示例。我懒得忙于自己的研究,有人能简单地告诉我:

  • “duck类型”和旧skool“variant类型”之间的区别,以及
  • 提供一个示例,说明我可能更喜欢duck类型而不是variant类型,以及
  • 提供一个我必须使用duck类型来完成的示例

我并不想因为怀疑这个“新”结构的力量而显得像禽鸟,我也不是因为拒绝做研究而回避这个问题,但我最近看到的关于它的蜂拥而至的炒作让我大吃一惊。在我看来,它似乎没有输入(也称为动态输入),所以我没有立即看到它的优点

附录:感谢迄今为止的示例。在我看来,使用诸如“O->can(Blah)”之类的东西相当于执行反射查找(这可能不便宜),和/或与编译器可以为您检查的(O是IBlah)差不多,但是后者的优点是可以区分我的IBlah接口和你的IBlah接口,而另外两个则没有。诚然,每个方法都有很多微小的接口,这会让事情变得一团糟,但检查许多单独的方法也是如此


…所以我还是不明白。它是一个神奇的省时工具,还是一个崭新的袋子里装着同样的旧东西?需要duck类型的示例在哪里?

duck类型只是动态类型或后期绑定的另一个术语。duck类型是一种变体对象,它使用运行时可能定义或不定义的任何成员访问权限(例如obj.anywhere)进行解析/编译。

我认为duck类型的核心是如何使用它。我们使用方法检测和实体的内省来知道如何处理它,而不是预先声明它将是什么(在那里您知道如何处理它)

它在OO语言中可能更实用,因为在OO语言中,原语不是原语,而是对象

我认为最好的总结方式是,在变体类型中,一个实体是/可以是任何东西,它是什么是不确定的,而不是一个实体只是看起来像任何东西,但你可以通过询问它来确定它是什么

有一件事我不相信不打字是可信的

sub dance { 
     my $creature = shift;
     if( $creature->can("walk") ){ 
         $creature->walk("left",1);
         $creature->walk("right",1); 
         $creature->walk("forward",1);
         $creature->walk("back",1);
     }
     if( $creature->can("fly") ){ 
          $creature->fly("up"); 
          $creature->fly("right",1); 
          $creature->fly("forward",1); 
          $creature->fly("left", 1 ); 
          $creature->fly("back", 1 ); 
          $creature->fly("down");
     } else if ( $creature->can("walk") ) { 
         $creature->walk("left",1);
         $creature->walk("right",1); 
         $creature->walk("forward",1);
         $creature->walk("back",1);
     } else if ( $creature->can("splash") ) { 
         $creature->splash( "up" ) for ( 0 .. 4 ); 
     }
     if( $creature->can("quack") ) { 
         $creature->quack();
     }
 }

 my @x = ();  
 push @x, new Rhinoceros ; 
 push @x, new Flamingo; 
 push @x, new Hyena; 
 push @x, new Dolphin; 
 push @x, new Duck;

 for my $creature (@x){

    new Thread(sub{ 
       dance( $creature ); 
    }); 
 }
任何其他方式都需要您对for函数设置类型限制,这将删除不同的种类,需要您为不同的种类创建不同的函数,这使得代码的维护非常困难

这真的很糟糕,仅仅是试图表现出良好的编舞

变量(至少我在VB6中使用过)包含一个单一的、定义良好的、通常是静态类型的变量。例如,它可能包含int、float或字符串,但变量int用作int,变量float用作float,变量字符串用作字符串

Duck类型改为使用动态类型。在duck类型下,如果变量恰好支持int、float或string在特定上下文中支持的特定方法,则变量可能可用作int、float或string

变体与duck类型的比较示例:

对于web应用程序,假设我希望我的用户信息来自LDAP而不是数据库,但我仍然希望我的用户信息可供基于数据库和ORM的web框架的其余部分使用

使用变体:没有运气。我可以创建一个变量,该变量可以包含UserFromDbRecord对象或UserFromLdap对象,但UserFromLdap对象将不可用于期望来自FromDbRecord层次结构的对象的例程


使用duck类型:我可以使用我的userfromdap类并添加几个方法,使其像UserFromDbRecord类一样工作。我不需要复制整个FromDbRecord接口,只需要复制我需要使用的例程即可。如果我做对了,这是一个非常强大和灵活的技术。如果我做错了,它会产生非常混乱和脆弱的代码(如果DB库或LDAP库发生更改,代码可能会被破坏)。

请阅读Wikipedia关于duck键入的文章的第一段。

我可以有一个接口(iRunTable)来定义Run()方法。
如果我有另一个类具有这样的方法:
public void runsomerunable(IRunnable rn){…}

在duck类型友好的语言中,我可以将任何具有Run()方法的类传入RunSomeRunnable()方法。
在静态类型语言中,传递到RunSomeRunnable的类需要显式实现IRunnable接口

interface IDuck {
  void Quack();
}
“如果它像鸭子一样跑”

变体至少更像.NET中的对象。

@Kent Fredric

通过使用显式接口,您的示例完全可以不用duck类型来完成……是的,更丑陋,但这并非不可能

就我个人而言,我发现在接口中有定义良好的契约比依赖duck类型更好地强制执行高质量的代码……但这只是我的观点,对此持保留态度

public interface ICreature { }
public interface IFly { fly();}
public interface IWalk { walk(); }
public interface IQuack { quack(); }
// ETC

// Animal Class
public class Duck : ICreature, IWalk, IFly, IQuack
{
    fly() {};
    walk() {};
    quack() {};
}

public class Rhino: ICreature, IWalk
{
    walk();
}

// In the method
List<ICreature> creatures = new List<ICreature>();
creatures.Add(new Duck());
creatures.Add(new Rhino());   

foreach (ICreature creature in creatures)
{
    if (creature is IFly)        
         (creature as IFly).fly();        
    if (creature is IWalk) 
         (creature as IWalk).walk();         
}
// Etc
公共接口ICreature{}
公共接口IFly{fly();}
公共接口IWalk{walk();}
公共接口i ack{quack();}
//等
//动物类
公共级鸭子:iFeature、IWalk、IFly、iPack
{
fly(){};
步行{};
庸医{};
}
公共级犀牛:ICreature,IWalk
{
步行();
}
//在方法中
列表生物=新列表();
添加(新鸭子());
添加(新犀牛());
foreach(生物中的特征生物)
{
如果(生物是IFly)
(作为IFly的生物)。飞行();
如果(生物是艾瓦克)
(作为我行走的生物)。行走();
}
//等

简单的答案是variant类型是弱类型的,而duck类型是强类型的

鸭型
class Daffy {
  void Quack() {
    Console.WriteLine("Thatsssss dispicable!!!!");
  }
}
IDuck d = new Daffy();
d.Quack();
struct foo
{
    int x;
    iny y;
    int z;
}

char * x = new char[100];
foo * pFoo = (foo *)x;
foo aRealFoo;
*pFoo = aRealFoo;
function Foo(x as object) as object
    return x.Quack()
end function