Programming languages 什么是鸭子打字?
我在网上阅读软件上的随机主题时遇到了duck-typing这个词,并没有完全理解它 什么是“duck typing”?这是一个在中使用的术语,但没有 其思想是,调用对象上的现有方法不需要类型——如果在对象上定义了方法,则可以调用它 这个名字来源于“如果它看起来像鸭子,嘎嘎叫起来像鸭子,那它就是鸭子”Programming languages 什么是鸭子打字?,programming-languages,duck-typing,Programming Languages,Duck Typing,我在网上阅读软件上的随机主题时遇到了duck-typing这个词,并没有完全理解它 什么是“duck typing”?这是一个在中使用的术语,但没有 其思想是,调用对象上的现有方法不需要类型——如果在对象上定义了方法,则可以调用它 这个名字来源于“如果它看起来像鸭子,嘎嘎叫起来像鸭子,那它就是鸭子” 有更多的信息。维基百科有一个相当详细的解释: duck类型是一种动态类型 键入对象的当前 方法和属性集 确定有效的语义,而不是 而不是从某个特定的 类或特定对象的实现 接口 重要的一点是,对于du
有更多的信息。维基百科有一个相当详细的解释: duck类型是一种动态类型 键入对象的当前 方法和属性集 确定有效的语义,而不是 而不是从某个特定的 类或特定对象的实现 接口 重要的一点是,对于duck类型,开发人员可能更关心使用的对象部分,而不是实际的底层类型 鸭型 这意味着一个操作没有正式指定其操作数必须满足的要求,而只是用给定的内容进行试验 与其他人所说的不同,这不一定与动态语言或继承问题有关 示例任务:调用对象上的某个方法
Quack
在不使用duck类型的情况下,执行此任务的函数f
必须事先指定其参数必须支持某种方法Quack
。一种常见的方法是使用接口
interface IQuack {
void Quack();
}
void f(IQuack x) {
x.Quack();
}
调用f(42)
失败,但是只要f(donald)
是i ack
子类型的实例,那么f(donald)
就可以工作
另一种方法是-但同样,方法Quack()
是正式指定的,任何不能提前证明它的东西都会导致编译器失败
def f(x : { def Quack() : Unit }) = x.Quack()
我们甚至可以写
f :: Quackable a => a -> IO ()
f = quack
在Haskell中,Quackable
typeclass确保了方法的存在
那么鸭式键入如何改变这一点呢 正如我所说的,duck类型系统并没有指定需求,只是在任何情况下进行尝试 因此,Python的动态类型系统总是使用duck类型:
def f(x):
x.Quack()
如果f
获得支持Quack()
的x
,则一切正常,否则将在运行时崩溃
但是duck类型根本不意味着动态类型——事实上,有一种非常流行但完全静态的duck类型方法也没有给出任何要求:
template <typename T>
void f(T x) { x.Quack(); }
模板
void f(tx){x.Quack();}
该函数不会以任何方式告诉您它需要一些能发出嘎嘎声的
x
,因此它只会在编译时尝试,如果一切正常,就可以了。我知道我没有给出一般性的答案。在Ruby中,我们不声明变量或方法的类型——一切都只是某种对象。
所以规则是“类不是类型”
在Ruby中,类从来都不是(好的,几乎从来都不是)类型。相反,对象的类型更多地由该对象的功能来定义。在Ruby中,我们称之为duck类型。如果一个对象走路像鸭子,说话像鸭子,那么解释器很乐意把它当作鸭子对待
例如,您可能正在编写一个例程,将歌曲信息添加到字符串中。如果您来自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)"
def append_宋(结果,宋)
#测试我们得到了正确的参数
除非结果。种类?(字符串)
失败类型错误。新建(“应为字符串”)结束
除非是歌曲。是什么?(歌曲)
失败类型错误。新建(“预期歌曲”)
结束
结果假设您正在设计一个简单的函数,该函数获取类型为Bird
的对象,并调用其walk()
方法。您可以想到两种方法:
这是我的函数,我必须确保它只接受Bird
类型,否则代码将无法编译。如果有人想使用我的函数,他们必须知道我只接受Bird
s
我的函数获取任何对象
,我只调用对象的walk()
方法。因此,如果对象
可以walk()
那么它是正确的。如果不能,我的功能就会失败。因此,这里不重要的是对象是鸟
或其他任何东西,重要的是它可以行走()
(这是duck类型)
必须考虑的是,duck类型在某些情况下可能有用。例如,Python经常使用duck类型
有用的读物
- Java、Python和JavaScript都有很好的duck类型示例
等等
- 这里还有一个很好的答案,描述了动态
打字及其缺点:
简单解释(无代码)
duck类型中重要的是对象实际可以做什么,而不是对象是什么
什么是鸭子打字?
“如果它走路像鸭子,嘎嘎叫像鸭子,那它就是鸭子。”-是的!但这意味着什么呢??!考虑这个例子:
Duck键入功能的示例:
想象一下我有一根魔杖。它有特殊的权力。如果我挥动魔杖,对一辆汽车说“开车!”
,那么,它就会开车
它对其他东西有用吗?不确定:所以我在卡车上试了一下。哇-它也能开车!然后我在飞机上、火车上和树林里(他们是一种人们用来“驾驶”高尔夫球的高尔夫球杆)试了试<他们都开车强>
但它能在茶杯上工作吗?错误:KAAAA-booooom!结果不太好。=>茶杯不能开车!!嗯
这基本上就是duck类型的概念。这是一个先试后买的系统。如果它起作用,一切都很好。但如果失败了,就像手榴弹还在你手里一样,它会在你脸上爆炸
换句话说,我们对o
def append_song(result, song)
result << song.title << " (" << song.artist << ")"
end
result = ""
append_song(result, song) # => "I Got Rhythm (Gene Kelly)"
interface StorageInterface
{
public function write(string $key, array $value): bool;
public function read(string $key): array;
}
class File implements StorageInterface
{
public function read(string $key): array {
//reading from a file
}
public function write(string $key, array $value): bool {
//writing in a file implementation
}
}
class Session implements StorageInterface
{
public function read(string $key): array {
//reading from a session
}
public function write(string $key, array $value): bool {
//writing in a session implementation
}
}
class Storage implements StorageInterface
{
private $_storage = null;
function __construct(StorageInterface $storage) {
$this->_storage = $storage;
}
public function read(string $key): array {
return $this->_storage->read($key);
}
public function write(string $key, array $value): bool {
return ($this->_storage->write($key, $value)) ? true : false;
}
}
$file = new Storage(new File());
$file->write('filename', ['information'] );
echo $file->read('filename');
$session = new Storage(new Session());
$session->write('filename', ['information'] );
echo $session->read('filename');
function __construct(StorageInterface $storage) ...
def traverse(t):
try:
t.label()
except AttributeError:
print(t, end=" ")
else:
# Now we know that t.node is defined
print('(', t.label(), end=" ")
for child in t:
traverse(child)
print(')', end=" ")
class MyAwesomeClass:
def __init__(self, str):
self.str = str
def __len__(self):
return len(self.str)
class MyNotSoAwesomeClass:
def __init__(self, str):
self.str = str
a = MyAwesomeClass("hey")
print(len(a)) # Prints 3
b = MyNotSoAwesomeClass("hey")
print(len(b)) # Raises a type error, object of type "MyNotSoAwesomeClass" has no len()