[NAME] ALL.dao.routine.decorator [TITLE] 修饰器函数 [DESCRIPTION] 修饰器函数是另一种特殊的函数。这种函数可通过修饰其它函数来增强其功能。 这种函数的修饰方式既 可修改原函数,也可返回新的函数。 函数可通过不同的途径被修饰,但只有在函数的定义处被修饰才会改变该函数。 其他方式都将生成新的 修改后的函数。 修饰器函数的定义跟普通函数的定义基本一样。不过它的函数名需要带@前缀, 且其第一个参数必须是一 函数类型。此函数类型将决定该修饰器函数可以修饰哪些类型的函数。 另外,第一个参数还需附带一个变 量名,以表示修饰后的函数被调用时的参数。 0.1 可修饰任意函数的修饰器函数 要定一个可修饰任意函数的修饰器函数,它的第一参数里的函数类型必须 最通用的函数类型routine。 这里是一个这样的简单的修饰器函数: 1 routine @Decorator( func(args): routine ) 2 { 3 io.writeln( 'Calling function:', std.about(func) ); 4 return func( args, ... ); # ... 参数扩展; 5 } 在函数定义的地方修饰函数: 1 @Decorator() 2 routine Function(){ io.writeln( 'Function()' ); } 修饰器函数的第二个及其后面的参数需放在@Decorator()的括号里。 被它修饰的函数将总作为第一个参 数传递给它。 如果修饰器函数不带除被修饰的函数之外的参数,它后面的括号可省略: 1 @Decorator 2 routine Function( a: int ){ io.writeln( 'Function(int)', a ); } 3 4 Function(); 5 Function(123); 0.2 修饰某些特定函数类型的修饰器函数 修饰器函数也可被定义为只能修饰某些特定函数类型的修饰器函数。 要这样定义,仅需将其第一个参数 里函数类型表达为所能修饰的函数类型即可。 下面定义的修饰器函数只能被用来修饰以整型为参数和字符串类型为返回值的函数。 这个修饰器函数还 定义了额外的参数,用来表示被修饰函数所期望的返回值。 1 routine @TestDecorator( func(args): routine<index:int=>string>, expected = '' ) 2 { 3 res = func( args, ... ); 4 io.writeln( res ); 5 io.writeln( 'Test result:', res == expected ? 'passed': 'failed' ); 6 return res; 7 } 8 9 @TestDecorator( 'Hello' ) 10 routine Hello( index = 0 ) 11 { 12 io.writeln( 'Calling Hello(int)' ); 13 return 'Hello'; 14 } 15 16 Hello(); 0.3 修饰器函数的重载 修饰器函数可以象普通函数那样根据参数进行重载。 下面是一个重载的修饰器函数,它只能用来修饰以字符串类型为参数且以整型为返回值的函数: 1 routine @TestDecorator( func(args): routine<name:string=>int>, expected = 0 ) 2 { 3 res = func( args, ... ); 4 io.writeln( res ); 5 io.writeln( 'Test result:', res == expected ? 'passed' : 'failed' ); 6 return res; 7 } # 多个修饰器函数可以连起来用: 1 @Decorator 2 @TestDecorator( 123 ) 3 routine Hello( name: string ) 4 { 5 io.writeln( 'Calling Hello(string)', name ); 6 return 123; 7 } 8 9 io.writeln( Hello( 'abc' ) ); 0.4 表达式里的函数修饰 修饰器函数可以按普通函数一样的方式用在表达式里。 也就是允许象调用普通函数那样调用修饰器函数 , 并将被修饰函数和其他值以参数的形式传递给修饰器函数。 1 anotherHello = @Decorator( Hello ) 这种方式修饰函数将产生新的修饰后的函数。 如果所有传递给修饰器函数的参数都为常量,那么这个函数修饰表达式 可在编译时求值。 1 const Hello3 = @Decorator( Hello ) 2 Hello3( 'def' ) 这个特性可用来修改从其他模块载入的函数,并使用同样的函数名。 1 load MyModule # 假定这个模块定义MyFunction()函数; 2 3 # 用函数修饰创建一个同名的新函数: 4 const MyFunction = @MyDecorator( MyFunction ) 在非常量表达式里修饰函数,函数的修饰将在运行时进行: 1 routine Hello2( index = 123 ) 2 { 3 io.writeln( 'Calling Hello2(int)', index ); 4 return 'Hello'; 5 } 6 # 运行时函数修饰: 7 func = @TestDecorator( Hello2, 'Hello' ); 8 io.writeln( '--------' ) 9 func(123) 10 11 func = @TestDecorator( func ); 12 io.writeln( '--------' ) 13 func(123) 也同普通函数一样,修饰器函数也可被赋与变量并在运行时使用。 1 deco = @Decorator; 2 func = deco( func ); 3 4 io.writeln( '--------' ) 5 func(789); 0.5 可修饰类成员方法的修饰器函数 修饰器函数也可用来修饰类成员方法。 这种修饰器函数即可定义在类外面,也可定义在类里面。 如果修饰器函数的被修饰函数类型部包括self参数, 那么它可被用来修饰类静态方法: 1 routine @StaticDecorator( meth(args) :routine<id:int=>int>, value = 123 ) 2 { 3 io.writeln( args, value ); 4 args.id = value; 5 return meth( args, ... ); 6 } 否则它可用来修饰类实例方法: 1 routine @MethodDecorator( meth(args) :routine<self:@T,id:int=>int>, value = 123 ) 2 { 3 io.writeln( args, value ); 4 args.id = value; 5 return meth( args, ... ); 6 } 当修饰器函数被定义在类里时,它必须被声明为静态方法。 因为它的第一个参数必须是被修饰函数类型 。 1 class Klass 2 { 3 static routine @ClassDecorator( meth(args) :routine<id:string=>?>, value = 'abc' ){ 4 io.writeln( args, value ); 5 args.id = value; 6 return meth( args, ... ); 7 } 8 9 @StaticDecorator( 456 ) 10 static routine StaticMeth( id :int ){ io.writeln( id ); return id } 11 12 @ClassDecorator 13 static routine StaticMeth( id :string ){ io.writeln( id ) } 14 15 @MethodDecorator( 789 ) 16 routine Meth( id :int ){ io.writeln( id ); return id } 17 } 18 19 Klass::StaticMeth( 0 ); 20 Klass::StaticMeth( 'a' ); 21 22 k = Klass(); 23 k.Meth(1);