Chinaunix首页 | 论坛 | 博客
  • 博客访问: 134904
  • 博文数量: 34
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 700
  • 用 户 组: 普通用户
  • 注册时间: 2014-11-12 16:52
文章分类

全部博文(34)

文章存档

2015年(13)

2014年(21)

我的朋友

分类: LINUX

2014-12-17 16:02:27

我提到了BASIC风格的语言中的变体型Variant。由于下述种种原因,在LotusScript中经常要用到变体型。

1.      函数的返回类型不能声明为数组,有此需要时只能用变体型。

2.      自定义对象的方法不支持重载,需要传入多种类型的参数时只能用变体型。

3.      数组变量不能整体赋值,例如从Split()或doc.ItemName,只能用变体型。

4.      需要写对多种数据类型通用的逻辑。

LotusScript是采用类定义(class definition,与JavaScript等语言的鸭子类型duck typing相对)的类型体系,在不使用变体型时,执行编译时类型检查,即静态类型检查(static type-checking);而一旦使用变体型,类型检查就被延迟到运行时,即动态类型检查(dynamic type-checking)。两种类型检察孰优孰劣,见仁见智。但是变体型在使用时与普通数据类型相比有许多不同之处和特殊的问题,值得专门指出。

赋值

LotusScript里给变量赋值,依据变量的数据类型,分为几种情况。

标量:包括各种数值类型、字符串、日期等单值,用Let语句赋值,Let通常被省略。

对象:包括产品对象(在Notes里即如NotesDocument的各类对象)、自定义对象和OLE对象,用Set语句赋值,Set不能被省略。

数组和列表:不能整体被赋值,只能对其单个元素赋值。是否要用Set由数组或列表元素的数据类型决定。

变体型:由所赋值的具体数据类型决定,如果是对象则要加Set。

用户定义数据类型(user-defined data types):与标量一样,用Let语句赋值,Let通常被省略。但是用户定义数据类型值不能被赋予变体型变量。

由上可见,因为变体型变量既能容纳标量,又能容纳对象,所以在赋值时是否加Set要根据所赋值的具体数据类型,而如果所赋值本身就是变体型,是否为对象在编译时不知道,就可能在运行时出现错误。须加Set未加时报错:SET required on class instance assignment。不得加Set加上时报错Typemismatch。

因此在为变体型赋变体型值前,须显式判断所赋值是否为对象。

  1. Sub SetValue(variable As Variant, value As Variant)  
  2.     If IsObject(value) Then  
  3.         Set variable=value  
  4.     Else  
  5.         variable=value  
  6.     End If  
  7. End Sub  
对象类型


在Java这样的完全面向对象的语言中,判断一个对象是否是某个类型有一个专门的运算符instanceof。LotusScript里也有一个类似的运算符IsA,但是却有一定的局限性。如果你在一个脚本库lib1里定义了某个对象类型MyClass,在另一个脚本库lib2里定义的某个函数Foo用到IsA,然后在一个代理中引用这两个脚本库,声明某个变量为MyClass类型,再将该变量传到Foo中,IsA运算的结果出人意料地为False。原因是IsA只能判断它所在的脚本环境知道的对象类型,MyClass没在lib2定义,lib2也没有引用lib1,所以对它来说,MyClass是未知的。解决方法是用TypeName函数,无论它要测试的对象类型在它运行的脚本环境里是否已知,都能准确地获得自定义对象的类型名称。所以我们可以写出如下的IsA的完善版:

  1. Function InstanceOf(v As Variant, className As StringAs Boolean  
  2.     If Not IsObject(v) Then  
  3.         InstanceOf=False  
  4.     Else  
  5.         Dim dt As Integer  
  6.         dt=DataType(v)  
  7.         If dt=V_LSOBJ Or dt=V_PRODOBJ Then  
  8.             If TypeName(v)=UCase(className) Then  
  9.                 InstanceOf=True  
  10.             Else  
  11.                 InstanceOf=False      
  12.             End If  
  13.         Else  
  14.             If v IsA className Then  
  15.                 InstanceOf=True  
  16.             Else  
  17.                 InstanceOf=False   
  18.             End If  
  19.         End If  
  20.     End If  
  21. End Function  


相等性

程序中变量的相等性(equality)可分为值的相等(value equality)和引用的相等(reference equality)。单值只有必要判断值是否相等,两个3之间没有任何区别。复合值(数组这样的容器以及对象)要比较所有成员的值是否相等,不仅代价高,而且因为私有字段,往往是不可能的。解决方案有两种,一是干脆比较对象的引用即地址是否相等,也就是任意两个对象变量只有指向的是同一个对象实例时才被认为是相等的。另一种途径是像Java中的对象那样有必要时重载Object的equals方法,提供具体的判断相等性的标准。以Java为例,==运算符用在单值时,比较值是否相等;用在对象时,比较引用是否相等。

回到LotusScript,变量的数据类型同样分成几大类。=运算符用于计算单值的相等性,Is运算符用于计算对象的相等性。数组和列表则完全不能整体比较,用哪个运算符都不允许(Type mismatch)。那么当我们要比较两个能容纳各种数据类型的变体型时,怎么办?只有分各种情况单独处理:

  1. Public Function Equals(v1 As Variant, v2 As VariantAs Boolean  
  2.     'Check data type  
  3.     Dim type1 As Integer, type2 As Integer  
  4.     'Type conversion for numericals, lists and arrays of variants     
  5.     type1=DataType4Equals(v1)  
  6.     type2=DataType4Equals(v2)  
  7.       
  8.     If type1>Then  
  9.         Equals=False          
  10.         Exit Function  
  11.     End If  
  12.       
  13.     'Empty or Null  
  14.     If type1=V_EMPTY Or type1= V_NULL Then   
  15.         Equals=True  
  16.         Exit Function   
  17.     End If  
  18.       
  19.     'Scalar  
  20.     If IsScalar(v1) Then  
  21.         If v1=v2 Then  
  22.             Equals=True  
  23.         Else  
  24.             Equals=False              
  25.         End If  
  26.         Exit Function   
  27.     End If  
  28.       
  29.     'Object  
  30.     If IsObject(v1) Then  
  31.         If v1 Is v2 Then  
  32.             Equals=True  
  33.         Else  
  34.             On Error ErrNamedMemberNonExist GoTo NotEquals  
  35.             If v1.IsEqualTo(v2) Then  
  36.                 Equals=True  
  37.             Else  
  38.                 Equals=False                  
  39.             End If  
  40.         End If  
  41.         Exit Function   
  42.     End If  
  43.       
  44.     'Array  
  45.     If IsArray(v1) Then  
  46.         'Check dimension numbers and bounds  
  47.         If Not ArrayBoundsEquals(v1, v2) Then  
  48.             Equals=False  
  49.             Exit Function             
  50.         End If  
  51.         'Change the arrays to one dimension  
  52.         Dim a1 As Variant, a2 As Variant  
  53.         a1=ArrayToOneDimension(v1)  
  54.         a2=ArrayToOneDimension(v2)  
  55.         Dim i As Integer  
  56.         For i=LBound(a1) To UBound(a1)  
  57.             If Not Equals(a1(i), a2(i)) Then  
  58.                 Equals=False  
  59.                 Exit Function                 
  60.             End If  
  61.         Next  
  62.           
  63.         Equals=True   
  64.         Exit Function         
  65.     End If  
  66.   
  67.     'List  
  68.     If IsList(v1) Then  
  69.         Dim tag As String         
  70.         ForAll e In v1  
  71.             tag=ListTag(e)  
  72.             If Not IsElement(v2(tag)) Then  
  73.                 Equals=False  
  74.                 Exit Function  
  75.             ElseIf Not Equals(e, v2(tag)) Then  
  76.                 Equals=False  
  77.                 Exit Function                 
  78.             End If  
  79.         End ForAll  
  80.           
  81.         Equals=True   
  82.         Exit Function         
  83.     End If  
  84.       
  85. NotEquals:  
  86.     Equals=False  
  87. End Function  
  88.   
  89. Private Function DataType4Equals(v As VariantAs Integer  
  90.     Dim result As Integer  
  91.     result=DataType(v)   
  92.     Select Case result  
  93.         Case V_BYTE, V_INTEGER, V_LONG, V_SINGLE, V_DOUBLE, V_CURRENCY  
  94.             result=V_CURRENCY  
  95.         Case Is > 8704 'Dynamic array  
  96.             result=8704  
  97.         Case Is > 8192 'Fixed array  
  98.             result=8192  
  99.         Case Is > 2048 'List  
  100.             result=2048  
  101.     End Select   
  102.     DataType4Equals=result  
  103. End Function  


上面两个函数合在一起能比较任意两个变体型是否相等。对单值,比较值的相等性。对数组和列表,依次比较每一个元素的相等性。对对象,如果该类型的对象定义了IsEqualTo方法,则调用该方法,否则比较引用的相等性。Null、Empty的比较已被覆盖。不同精度的数值型之间的转换也已考虑。
更多精彩内容请浏览

阅读(692) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~