题
我理解一个使用"祝福"关键字在Perl内部一类的"新的"方法:
sub new {
my $self = bless { };
return $self;
}
但到底是什么"祝福"做到,哈希考?
其他提示
bless
伙伴参与一个软件包。
什么并不重要基准是,它可以向哈希(最常见的情况下),以一阵(不是那么常见),向一个标(通常这表示一个 里面出来的对象),定期表达的子程序或TYPEGLOB(见的书 面向对象的Perl:一个全面的指导的概念和编程技术的达米安*康威 为有用的例子)或甚至参考文件或目录的处理(最常见的情况)。
效果 bless
-ing是,它可以应用的特殊法到祝福的参考。
例如,如果一个幸福的参照储存在 $obj
(有关通过 bless
具包"类"),然后 $obj->foo(@args)
将呼叫一个子程序 foo
并通过作为第一个参数的基准 $obj
随后通过的其他参数(@args
).子程序应当定在包装"类"。如果没有子程序 foo
在包"类",一个名单的其他软件包(所采取的形式阵列 @ISA
在包"一级")将被搜查,第一个子程序 foo
发现将被称为。
短版本:它标志着散列作为附加到当前包命名空间(以使得包提供它的类的实现)
。此函数告诉由REF引用的实体,它现在是在CLASSNAME封装的对象,或当前包如果省略CLASSNAME。建议保佑的两参数形式的使用。
示例强>:
bless REF, CLASSNAME
bless REF
<强>返回值强>
此函数返回参照祝福成CLASSNAME的对象。
示例强>:
以下是示出其基本用法的示例代码,对象基准由福来包的类的引用创建 -
#!/usr/bin/perl
package Person;
sub new
{
my $class = shift;
my $self = {
_firstName => shift,
_lastName => shift,
_ssn => shift,
};
# Print all the values just for clarification.
print "First Name is $self->{_firstName}\n";
print "Last Name is $self->{_lastName}\n";
print "SSN is $self->{_ssn}\n";
bless $self, $class;
return $self;
}
我会在这里提供一个答案,因为这里的人并没有完全按一下我。
Perl的保佑功能相关联的包内的所有功能的任何引用。
为什么我们需要这个?
让我们开始在JavaScript中表达的示例:
(() => {
'use strict';
class Animal {
constructor(args) {
this.name = args.name;
this.sound = args.sound;
}
}
/* [WRONG] (global scope corruption)
* var animal = Animal({
* 'name': 'Jeff',
* 'sound': 'bark'
* });
* console.log(animal.name + ', ' + animal.sound); // seems good
* console.log(window.name); // my window's name is Jeff?
*/
// new is important!
var animal = new Animal(
'name': 'Jeff',
'sound': 'bark'
);
console.log(animal.name + ', ' + animal.sound); // still fine.
console.log(window.name); // undefined
})();
现在让剥去类构建体和使没有它:
(() => {
'use strict';
var Animal = function(args) {
this.name = args.name;
this.sound = args.sound;
return this; // implicit context hashmap
};
// the "new" causes the Animal to be unbound from global context, and
// rebinds it to an empty hash map before being constructed. The state is
// now bound to animal, not the global scope.
var animal = new Animal({
'name': 'Jeff',
'sound': 'bark'
});
console.log(animal.sound);
})();
该函数将无序属性的哈希表(因为它是没有意义的有在2016年的动态语言的特定顺序写入性能),并返回一个哈希表的属性,或者如果你忘了把新关键字,它会返回整个全局上下文(例如,窗口中的浏览器或全球中的NodeJS)。
Perl有没有“这个”,也不是“新”,也不是“类”,但它仍然可以具有类似的行为的函数。我们不会有一个构造函数也没有原型,但我们将能够随意创建新的动物和修改他们的个人属性。
# self contained scope
(sub {
my $Animal = (sub {
return {
'name' => $_[0]{'name'},
'sound' => $_[0]{'sound'}
};
});
my $animal = $Animal->({
'name' => 'Jeff',
'sound' => 'bark'
});
print $animal->{sound};
})->();
现在,我们有一个问题:如果我们希望动物本身,而不是我们的打印他们的声音是怎样执行的声音。也就是说,我们希望有一个功能performSound,打印动物自身的声音。
要做到这一点的一种方式是通过教每个人的动物如何做到这一点的声音。这意味着每个年龄组有它自己的重复功能performSound。
# self contained scope
(sub {
my $Animal = (sub {
$name = $_[0]{'name'};
$sound = $_[0]{'sound'};
return {
'name' => $name,
'sound' => $sound,
'performSound' => sub {
print $sound . "\n";
}
};
});
my $animal = $Animal->({
'name' => 'Jeff',
'sound' => 'bark'
});
$animal->{'performSound'}();
})->();
因为performSound被每个动物被构造时间把作为一个完全新的函数对象这是不好的。 10000只动物指10000个performSounds。我们希望有一个用于通过查找自己的声音和打印所有动物单一功能performSound它。
(() => {
'use strict';
/* a function that creates an Animal constructor which can be used to create animals */
var Animal = (() => {
/* function is important, as fat arrow does not have "this" and will not be bound to Animal. */
var InnerAnimal = function(args) {
this.name = args.name;
this.sound = args.sound;
};
/* defined once and all animals use the same single function call */
InnerAnimal.prototype.performSound = function() {
console.log(this.name);
};
return InnerAnimal;
})();
/* we're gonna create an animal with arguments in different order
because we want to be edgy. */
var animal = new Animal({
'sound': 'bark',
'name': 'Jeff'
});
animal.performSound(); // Jeff
})();
下面是其中平行于Perl的有点停止。
JavaScript的新的运营商不是可选的,没有它,“这”对象方法内部破坏全球范围:
(() => {
// 'use strict'; // uncommenting this prevents corruption and raises an error instead.
var Person = function() {
this.name = "Sam";
};
// var wrong = Person(); // oops! we have overwritten window.name or global.main.
// console.log(window.name); // my window's name is Sam?
var correct = new Person; // person's name is actually stored in the person now.
})();
我们希望有一个函数,该函数查找该动物自身的声音,而不是在建设硬编码的每个动物。
祝福让我们使用包作为对象的原型。这种方式中,对象是知道“包”的它是“参考”,进而可以在包“伸入”从“包对象”的构造中创建的特定实例的功能:
package Animal;
sub new {
my $packageRef = $_[0];
my $name = $_[1]->{'name'};
my $sound = $_[1]->{'sound'};
my $this = {
'name' => $name,
'sound' => $sound
};
bless($this, $packageRef);
return $this;
}
# all animals use the same performSound to look up their sound.
sub performSound {
my $this = shift;
my $sound = $this->{'sound'};
print $sound . "\n";
}
package main;
my $animal = Animal->new({
'name' => 'Cat',
'sound' => 'meow'
});
$animal->performSound();
<强>概要/ TL; DR 强>:
Perl有没有 “这个”, “类”,也不是 “新的”。福一个目的是一个包给出了对象到包的引用,并且当它调用在包的功能,它们的参数将通过1个时隙偏移,并且所述第一参数($ _ [0]或移位)将等同于JavaScript的“本”。反过来,你可以在一定程度模拟JavaScript的原型模型。
不幸的是,就不可能(我的理解),以在运行时创建的“新阶级”,因为你需要每一个“类”有它自己的包,而在JavaScript中,你不需要包所有的,因为“新的”关键词构成了一个匿名的HashMap让你在运行时作为一个整体使用,你可以在飞行中增加新的功能和删除功能。
有一些Perl库创建他们自己在表现桥接此限制的方式,如麋。
<强>为什么混乱强>:
由于包。我们的直觉告诉我们的对象绑定到包含其原型HashMap中。这让我们在像JavaScript可以运行时创建“套餐”。 Perl不具有这种灵活性(至少不是建在,你必须去创造它或从其他模块得到它),并依次运行时表现的阻碍。称其为“祝福”不去做太多好处也没有。
我们想要做什么
这样的事情,但具有结合到原型图递归的,隐式地绑定到原型而不必显式地做到这一点。
下面是它天真的尝试:问题是,“呼”做ES不知道“是什么把它称为”,因此它也可以被通用Perl函数“objectInvokeMethod(对象,方法)”,它会检查对象是否有方法,或它的原型,或者其原型有它,直到它到达末尾,并发现它或没有(原型的传承)。 Perl有很好的eval魔术做,但我会留给的东西,我可以尝试这样做。
反正这里的理念是:
(sub {
my $Animal = (sub {
my $AnimalPrototype = {
'performSound' => sub {
return $_[0]->{'sound'};
}
};
my $call = sub {
my $this = $_[0];
my $proc = $_[1];
if (exists $this->{$proc}) {
return $this->{$proc}->();
} else {
return $this->{prototype}->{$proc}->($this, $proc);
}
};
return sub {
my $name = $_[0]->{name};
my $sound = $_[0]->{sound};
my $this = {
'this' => $this,
'name' => $name,
'sound' => $sound,
'prototype' => $AnimalPrototype,
'call' => $call
};
};
})->();
my $animal = $Animal->({
'name' => 'Jeff',
'sound'=> 'bark'
});
print($animal->{call}($animal, 'performSound'));
})->();
总之希望有人会发现这篇文章非常有用。
我在此之后思想指导开发的面向对象的Perl。
保佑与类的任何数据结构参考相关联。鉴于它如何Perl的创建继承结构(在一种树)是容易把对象模型的优点是用组合物中创建对象。
有关此关联,我们称为对象,始终发展具有记住该对象和类行为的内部状态被分离。你可以保佑/允许任何数据参考使用任何包/类的行为。 由于封装可了解对象的“情绪”的状态。
例如,如果可以确信任何错误物体将是一个幸福的散列,可以(最后!)填写中的Bug遗漏码:: print_me方法:
package Bug;
sub print_me
{
my ($self) = @_;
print "ID: $self->{id}\n";
print "$self->{descr}\n";
print "(Note: problem is fatal)\n" if $self->{type} eq "fatal";
}
现在,每当print_me方法是通过给一个已经祝福到Bug类的任何散列的引用调用时,$自变量提取这是作为第一个参数传递,然后将打印语句访问的各种条目的参考祝福哈希值。