鸭子类型在软件开发中意味着什么?
当前回答
简单的解释
鸭子打字是什么?
“如果它走路像鸭子,嘎嘎叫像....等等”——是的,但这是什么意思??!
我们感兴趣的是“对象”能做什么,而不是它们是什么。
让我们用一个例子来分解它:
详情见下文:
Duck Typing功能示例:
想象我有一根魔杖。它有特殊的力量。如果我挥舞魔杖,对一辆车说“开车!”,那么,它就会开车!
它对其他东西有用吗?不确定,所以我在卡车上试了试。哇,它也能开车!然后我在飞机上、火车上和1 Woods(这是一种人们用来“驾驶”高尔夫球的高尔夫球杆)上尝试了一下。他们都开车!
但它能用在茶杯上吗?错误:KAAAA-BOOOOOOM !结果不太好。====>茶杯不能开车!!咄! ?
这就是duck typing的基本概念。这是一个先试后买的系统。如果有效,一切都好。但如果失败了,就像手榴弹还在你手上一样,它会在你脸上爆炸。
换句话说,我们感兴趣的是对象能做什么,而不是对象是什么。
那么像c#或Java等语言呢?
如果我们关心的对象实际上是什么,那么我们的魔术只会对预先设置的,授权的类型起作用——在这种情况下是汽车,但对其他可以驾驶的对象无效:卡车,轻便摩托车,突突车等。它不能在卡车上工作,因为我们的魔杖期望它只能在汽车上工作。
换句话说,在这种情况下,魔杖非常仔细地观察物体是什么(它是一辆汽车吗?),而不是物体能做什么(例如汽车、卡车等能不能开车)。
让卡车驾驶的唯一方法是,如果您能够以某种方式让魔杖同时期待卡车和汽车(也许通过“实现一个公共接口”)。这可以通过一种叫做“多态”的技术来实现,也可以通过使用“接口”来实现——它们是一样的东西。如果你喜欢漫画,想要一个解释,看看我关于界面的漫画。
总结:关键外卖
在duck类型中,重要的是对象实际上可以做什么,而不是对象是什么。
序言
我试图通过去除迂腐的细微差别和学术语言来保持它的简单/有趣。这种方法并不适合所有人——如果你更喜欢学术定义,可以看看维基百科上关于“回避输入”的文章,或者《心灵捕手》中马特·达蒙对“回避输入”的解释;)
代码示例
但是高尔夫球杆怎么能像汽车一样“驾驶”呢?他们不一样吗?但如果你使用的是Ruby这样的语言:
class Car
def drive
"I"m driving a Car!"
end
end
class GolfClub
def drive
"I"m driving a golf club!"
end
end
def test_drive(item)
item.drive # don't care what it is, all i care is that it can "drive"
end
car = Car.new
test_drive(car) #=> "I'm driving a Car"
club = GolfClub.new
test_drive(club) #=> "I"m driving a GolfClub"
其他回答
简单的解释
鸭子打字是什么?
“如果它走路像鸭子,嘎嘎叫像....等等”——是的,但这是什么意思??!
我们感兴趣的是“对象”能做什么,而不是它们是什么。
让我们用一个例子来分解它:
详情见下文:
Duck Typing功能示例:
想象我有一根魔杖。它有特殊的力量。如果我挥舞魔杖,对一辆车说“开车!”,那么,它就会开车!
它对其他东西有用吗?不确定,所以我在卡车上试了试。哇,它也能开车!然后我在飞机上、火车上和1 Woods(这是一种人们用来“驾驶”高尔夫球的高尔夫球杆)上尝试了一下。他们都开车!
但它能用在茶杯上吗?错误:KAAAA-BOOOOOOM !结果不太好。====>茶杯不能开车!!咄! ?
这就是duck typing的基本概念。这是一个先试后买的系统。如果有效,一切都好。但如果失败了,就像手榴弹还在你手上一样,它会在你脸上爆炸。
换句话说,我们感兴趣的是对象能做什么,而不是对象是什么。
那么像c#或Java等语言呢?
如果我们关心的对象实际上是什么,那么我们的魔术只会对预先设置的,授权的类型起作用——在这种情况下是汽车,但对其他可以驾驶的对象无效:卡车,轻便摩托车,突突车等。它不能在卡车上工作,因为我们的魔杖期望它只能在汽车上工作。
换句话说,在这种情况下,魔杖非常仔细地观察物体是什么(它是一辆汽车吗?),而不是物体能做什么(例如汽车、卡车等能不能开车)。
让卡车驾驶的唯一方法是,如果您能够以某种方式让魔杖同时期待卡车和汽车(也许通过“实现一个公共接口”)。这可以通过一种叫做“多态”的技术来实现,也可以通过使用“接口”来实现——它们是一样的东西。如果你喜欢漫画,想要一个解释,看看我关于界面的漫画。
总结:关键外卖
在duck类型中,重要的是对象实际上可以做什么,而不是对象是什么。
序言
我试图通过去除迂腐的细微差别和学术语言来保持它的简单/有趣。这种方法并不适合所有人——如果你更喜欢学术定义,可以看看维基百科上关于“回避输入”的文章,或者《心灵捕手》中马特·达蒙对“回避输入”的解释;)
代码示例
但是高尔夫球杆怎么能像汽车一样“驾驶”呢?他们不一样吗?但如果你使用的是Ruby这样的语言:
class Car
def drive
"I"m driving a Car!"
end
end
class GolfClub
def drive
"I"m driving a golf club!"
end
end
def test_drive(item)
item.drive # don't care what it is, all i care is that it can "drive"
end
car = Car.new
test_drive(car) #=> "I'm driving a Car"
club = GolfClub.new
test_drive(club) #=> "I"m driving a GolfClub"
我看到很多答案都在重复这句老话:
如果它长得像鸭子,叫声也像鸭子,那它就是鸭子
然后深入解释可以使用duck typing做什么,或者一个似乎进一步混淆了概念的示例。
我觉得没什么用。
这是我发现的关于鸭子打字的最好的简单英语回答:
Duck Typing意味着对象是根据它能做什么来定义的,而不是根据它能做什么来定义的 它是什么。
这意味着我们不太关心对象的类/类型,而更关心可以对其调用哪些方法以及可以对其执行哪些操作。我们不关心它的类型,我们只关心它能做什么。
Duck typing 意味着一个操作没有正式指定其操作数必须满足的要求,而只是使用给定的条件进行尝试。
与其他人所说的不同,这并不一定与动态语言或继承问题有关。
示例任务:在对象上调用某个方法Quack。
如果不使用duck-typing,执行此任务的函数f必须事先指定其参数必须支持某种方法Quack。常用的方法是使用接口
interface IQuack {
void Quack();
}
void f(IQuack x) {
x.Quack();
}
调用f(42)失败,但f(donald)工作,只要donald是一个iquack子类型的实例。
另一种方法是结构类型—但同样,方法Quack()是正式指定的,任何不能提前证明它是嘎嘎作响的东西都会导致编译器失败。
def f(x : { def Quack() : Unit }) = x.Quack()
我们甚至可以写成
f :: Quackable a => a -> IO ()
f = quack
在Haskell中,Quackable类型类确保了方法的存在。
So how does **duck typing** change this?
好吧,正如我所说的,duck输入系统不指定需求,而只是尝试任何可行的方法。
因此,像Python这样的动态类型系统总是使用duck类型:
def f(x):
x.Quack()
如果f得到一个支持Quack()的x,一切正常,否则,它将在运行时崩溃。
但是鸭子类型并不意味着动态类型——事实上,有一种非常流行但完全静态的鸭子类型方法,它也没有给出任何要求:
template <typename T>
void f(T x) { x.Quack(); }
该函数没有以任何方式告诉它想要某个可以Quack的x,所以它只是在编译时尝试,如果一切正常,就没问题。
我知道我没有给出一个笼统的答案。在Ruby中,我们不声明变量或方法的类型——所有东西都是某种类型的对象。 规则是"类不是类型"
在Ruby中,类从来都不是(好吧,几乎从来都不是)类型。相反,对象的类型更多地由该对象可以做什么来定义。在Ruby中,我们称之为duck typing。如果一个对象像鸭子一样走路,像鸭子一样说话,那么解释器很乐意把它当作鸭子来对待。
例如,您可能正在编写一个例程,将歌曲信息添加到字符串中。如果你有c#或Java背景,你可能会这样写:
def append_song(result, song)
# test we're given the right parameters
unless result.kind_of?(String)
fail TypeError.new("String expected") end
unless song.kind_of?(Song)
fail TypeError.new("Song expected")
end
result << song.title << " (" << song.artist << ")" end
result = ""
append_song(result, song) # => "I Got Rhythm (Gene Kelly)"
采用Ruby的鸭子输入,您可以编写一些简单得多的东西:
def append_song(result, song)
result << song.title << " (" << song.artist << ")"
end
result = ""
append_song(result, song) # => "I Got Rhythm (Gene Kelly)"
你不需要检查参数的类型。如果它们支持<<(在结果的情况下)或标题和艺术家(在歌曲的情况下),一切都会正常工作。如果没有,你的方法无论如何都会抛出一个异常(就像你检查了类型一样)。但如果没有检查,你的方法突然变得灵活多了。你可以向它传递一个数组、一个字符串、一个文件或任何其他使用<<追加的对象,它就可以工作了。
维基百科有相当详细的解释:
http://en.wikipedia.org/wiki/Duck_typing
鸭子打字是一种动态的风格 输入一个对象的电流 方法和属性集 而是确定有效的语义 比它从一个特定的继承 类的实现 接口。
重要的是,使用duck类型时,开发人员可能更关心被使用的对象部分,而不是实际的底层类型是什么。