30 May 2005
This post may be outdated due to it was written on 2005. The links may be broken. The code may be not working anymore. Leave comments if needed.

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 来实现代码复用)。
  1. 类是用 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;
        ...
    }
  2. 属性和私有属性。一个简单的例子:
    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
    
    has $.name 类似于生成一个具有同样名字(name)的存取器。
    is rw 等后缀属性将复制为存取器的后缀属性。这里的 is rw 将使 name 存取器为左值方法(Lvaule method)。
    默认的存取器是只读的。简便设定所有属性为 is rw 的话可以在 class Dog 后加 is rw.
  3. 方法和私有方法。我们用 method 来定义方法(我们以前面的例子为基础):
    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);
    method 其实可以算做 sub 的一种,所不同的是 method 是放在 class/role 里的。
    定义私有方法与定义私有属性类似,在方法前加 :. 如 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);
        }
    }
  4. 类的智能匹配。如果你想确定某一变量是不是某一类的话,可以使用 ~~ 智能匹配。如前面的 $pet:
    if $pet ~~ Dog { say "$pet is a dog"; }

see u tomorrow

I'll add something later. have fun!


blog comments powered by Disqus