[NAME] ALL.dao.type.variant [TITLE] 多型(Variant)类型 [DESCRIPTION] 一个多型(Variant或Disjoint Union)类型可用来标注一个变量的多个可能类型。 多型类型的表示由多 个类型名通过|组合起来。 一个多型类型的变量可保存其任意一种可能类型的值。 例如: 1 var intstr : int|string = 123 2 intstr = 'abc' 值得注意的是多型类型通常不支持它的可能类型的运算操作。它必须作适当的转换 才能用它真实类型的 运算操作。 要检查一个值的类型,并根据不同的类型作不同的操作,最简单的办法是使用 基于类型的 switch-case: 1 switch( intstr ) type { 2 case int : io.writeln( intstr * 1000 ) 3 case string : io.writeln( intstr + 'abcdefg' ) 4 } 这里每个类型项的代码块里,变量intstr可直接按相应的类型使用 而不作显式的转换。 不过,当一个多型类型仅有两个类型组成,并且其中之一为空值none类型, 那么这个多型类型可直接作另 一类型使用而不需显式转换。 1 routine Test( maybelist: list<int>|none ) 2 { 3 if( maybelist == none ) return 4 maybelist.append( 123 ) # 用作list<int>,无显式转换; 5 } 上面提到的类型switch有两个变体: 1 switch( var name = expression ) type { 2 ... 3 } 4 switch( invar name = expression ) type { 5 ... 6 } 这俩都将声明一个仅在switch块里可用的变量名。 不过后者声明的是一个定变量,可防止该变量在swit ch块被修改。 更多例子: 1 intstring: list<int|string> = {}; 2 3 intstring.append( 123 ); 4 intstring.append( 'abc' ); 5 6 #intstring.append( {} ); # typing error 7 8 io.writeln( intstring, intstring[0], intstring[1] ); 1 interface HasSizeMethod 2 { 3 routine Size()=>int; 4 } 5 class AA 6 { 7 routine Size()=>int{ return 10 } 8 } 9 class BB 10 { 11 routine Size()=>int{ return 20 } 12 } 13 14 routine Test( object: AA|BB|HasSizeMethod ) 15 { 16 # casting to an interface will invoke automatic binding: 17 var object2 = (HasSizeMethod) object; 18 io.writeln( object2.Size() ) 19 } 20 21 io.writeln( std.about( Test ) ); 22 23 Test( AA() ) 24 Test( BB() ) 25 26 routine Test2( data: int|float|string ) 27 { 28 switch( data ) type { 29 case int : io.writeln( 'handling int' ); 30 case float : io.writeln( 'handling float' ); 31 case string : io.writeln( 'handling string' ); 32 } 33 } 34 35 Test2( 1 ); 36 Test2( 1.0F ); 37 Test2( 'abc' ); 1 class FakeImage 2 { 3 var image = [1,2,3,4;5,6,7,8;11,12,13,14;15,16,17,18]; 4 5 # instead of writing operator methods with all the combinations 6 # such as tuple<int,int>, tuple<int,none>, ... 7 # one can use disjoint union to simplify this. 8 operator[]( i: int, js: tuple<int|none,int|none> )=>array<int> 9 { 10 # one can simply return image[i,js], but the following is for demonstration purpose: 11 var j1 = 0; 12 var j2 = image.dim(1) - 1; 13 if( js[0] != none ) j1 = js[0]; 14 if( js[1] != none ) j2 = js[1]; 15 return image[i,j1:j2]; 16 } 17 } 18 19 var image = FakeImage(); 20 io.writeln( image[1,1:] ); 21 io.writeln( image[2,:1] ); 1 routine Sum( alist : list<@T<int|string>> ) => @T 2 { 3 # reflect.trace(); 4 return alist.sum(); 5 } 6 7 var s = Sum( { 1, 2, 3 } ); 8 #s += 'a'; # typing error 9 io.writeln( s ); 10 11 var s2 = Sum( { 'a', 'b', 'c' } ); 12 io.writeln( s2 );