Category: Perl6 Keywords: class Perl6
Declare
我开始打算讲 Perl 6 中新的面对对象技术。如果有些新的知识碰到了而前面没讲过,我会穿插着讲点那方面的知识。最重要的声明是:我不保证我所写的东西是正确的。所以各位看官如果发现错误请给我发电子邮件(fayland at gmail.com)。
sit down, now comes class. :>
在 Perl 5 中对象,模块,类,包的概念是混在一起的,没有区分开来:- 一个对象只是一个 bless 的引用
- 一个类 class 只是一个包 package
- 一个方法 method 只是一个子程序 sub
- 一个模块 module 只是一个与 package 名一样的文件
在 Perl 6 中他们将都各自拥有自己的关键字。模块有 module 类有 class 方法有 method 对象有 object.
暂时不介绍它们是什么,先讲几个概念:- 子程序。关键字 sub, 是带有参数列表的不可继承例程。
- 方法。关键字 method, 是可继承的例程,它总是有一个对应的对象(称之为调用者)和属于一个特定的类。
- 子方法。关键字 submethod, 是不可继承的方法,或者说是化装成方法的子程序。它也有调用者和所属的特定类。
- 多重方法/Multimethods. 关键字 multi, 它的特点是可以有一个或多个调用者。
- 规则。关键字 rule, 是一种用于模式匹配的带语法的方法。它的对应块有特殊的语法。(以后详细说)
- 宏。关键字 macro, 是一种当它们被解析时(编译时)就运行的例程。宏可能返回另一个源代码字符串或解析树。
- 角色。关键字 role, 主要用于代码复用。(以后详细说)
class
先讲类,类主要用于实例(对象)管理,其次才是软件复用(通过继承或委派来实现,我们一般用 role 来实现代码复用)。- 类是用 class 声明的。它有两种声明方式:
class Foo; # 文件下面的部分都是类的定义 ... class Bar {...} # 块里才是类的定义部分我们通过 is 来继承类(可以多重继承),用 does 来复用 role. 简单的例子如下:class Dog is Mammal is Pet; # 继承 Mammal 继承 Pet class Dog is Mammal does Pet { # Pet 是一个 role # 另一种方式: class Dog { is Mammal; does Pet; ... } - 属性和私有属性。一个简单的例子:
has $.name 类似于生成一个具有同样名字(name)的存取器。class Dog { has $.name is rw; has $.mum; # 没有 is rw 的话只能在 class 里改这个数据 has $:age; # 私有属性,可以后面加 = 1' 来设置默认值,上面的属性也一样 } my $pet = Dog.new( :name<Snoopy>, :mum<Kitty>, :age<2> ); # 另一种方式 # my Dog $pet .= new( :name<Snoopy>, :mum<Kitty>, :age<2> ); say $pet.name; # Snoopy say $pet.mum; # Kitty # say $pet.age; # WRONG, age 为私有变量 $pet.name = 'Shakespeare'; # 设置属性 name 的值 say $pet.name; # Shakespeare # $pet.mum = 'Hella'; # WRONG, 默认 mum 是只读的。如果要在类外面更改 mum, 必须设置它为 is rw
is rw 等后缀属性将复制为存取器的后缀属性。这里的 is rw 将使 name 存取器为左值方法(Lvaule method)。
默认的存取器是只读的。简便设定所有属性为 is rw 的话可以在 class Dog 后加 is rw. - 方法和私有方法。我们用 method 来定义方法(我们以前面的例子为基础):
method 其实可以算做 sub 的一种,所不同的是 method 是放在 class/role 里的。Class Dog { ... method grow (?$year = 1) { $:age += $year; say "$year year past, now $.name is $:age years old"; } } my $pet = Dog.new( :name<Eric>, :age<2> ); $pet.grow; # 1 year past, now Eric is 3 years old $pet.grow(2); # 2 year past, now Eric is 5 years old # 除了这种调用方法外,我么还可以这么调用(间接调用) grow $pet: 2; grow $pet:(3);
定义私有方法与定义私有属性类似,在方法前加 :. 如 mehod :MyPrivateMethod {...}
甚至定义私有类也可以这样:class :MyPrivateClass {...}内部方法的调用:
class Dog { has $.name; has $:age; method grow (?$year = 1) { $:age += $year; say "$year year past, now $.name is $:age years old"; .:sigh; # 等同于 $_.:sigh } method :sigh { say "$.name is too old" if ($:age > 7); } } - 类的智能匹配。如果你想确定某一变量是不是某一类的话,可以使用 ~~ 智能匹配。如前面的 $pet:
if $pet ~~ Dog { say "$pet is a dog"; }