zoukankan      html  css  js  c++  java
  • 87. 再谈变体型Variant

    85. BASIC和LotusScript中的Variant一文中。我提到了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。

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

    Sub SetValue(variable As Variant, value As Variant)
    	If IsObject(value) Then
    		Set variable=value
    	Else
    		variable=value
    	End If
    End Sub
    对象类型

    在Java这种全然面向对象的语言中,推断一个对象是否是某个类型有一个专门的运算符instanceof。LotusScript里也有一个相似的运算符IsA,可是却有一定的局限性。

    假设你在一个脚本库lib1里定义了某个对象类型MyClass。在还有一个脚本库lib2里定义的某个函数Foo用到IsA,然后在一个代理中引用这两个脚本库。声明某个变量为MyClass类型。再将该变量传到Foo中,IsA运算的结果出人意料地为False。原因是IsA仅仅能推断它所在的脚本环境知道的对象类型,MyClass没在lib2定义,lib2也没有引用lib1。所以对它来说,MyClass是未知的。

    解决方法是用TypeName函数,不管它要測试的对象类型在它执行的脚本环境里是否已知,都能准确地获得自己定义对象的类型名称。

    所以我们能够写出例如以下的IsA的完好版:

    Function InstanceOf(v As Variant, className As String) As Boolean
    	If Not IsObject(v) Then
    		InstanceOf=False
    	Else
    		Dim dt As Integer
    		dt=DataType(v)
    		If dt=V_LSOBJ Or dt=V_PRODOBJ Then
    			If TypeName(v)=UCase(className) Then
    				InstanceOf=True
    			Else
    				InstanceOf=False	
    			End If
    		Else
    			If v IsA className Then
    				InstanceOf=True
    			Else
    				InstanceOf=False 
    			End If
    		End If
    	End If
    End Function

    相等性

    程序中变量的相等性(equality)可分为值的相等(value equality)和引用的相等(reference equality)。

    单值仅仅有必要推断值是否相等,两个3之间没有不论什么差别。

    复合值(数组这种容器以及对象)要比較全部成员的值是否相等,不仅代价高,并且由于私有字段,往往是不可能的。解决方式有两种。一是干脆比較对象的引用即地址是否相等,也就是随意两个对象变量仅仅有指向的是同一个对象实例时才被觉得是相等的。还有一种途径是像Java中的对象那样有必要时重载Object的equals方法,提供详细的推断相等性的标准。以Java为例,==运算符用在单值时。比較值是否相等。用在对象时,比較引用是否相等。

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

    Public Function Equals(v1 As Variant, v2 As Variant) As Boolean
    	'Check data type
    	Dim type1 As Integer, type2 As Integer
    	'Type conversion for numericals, lists and arrays of variants	
    	type1=DataType4Equals(v1)
    	type2=DataType4Equals(v2)
    	
    	If type1><type2 Then
    		Equals=False		
    		Exit Function
    	End If
    	
    	'Empty or Null
    	If type1=V_EMPTY Or type1= V_NULL Then 
    		Equals=True
    		Exit Function 
    	End If
    	
    	'Scalar
    	If IsScalar(v1) Then
    		If v1=v2 Then
    			Equals=True
    		Else
    			Equals=False 			
    		End If
    		Exit Function 
    	End If
    	
    	'Object
    	If IsObject(v1) Then
    		If v1 Is v2 Then
    			Equals=True
    		Else
    			On Error ErrNamedMemberNonExist GoTo NotEquals
    			If v1.IsEqualTo(v2) Then
    				Equals=True
    			Else
    				Equals=False 				
    			End If
    		End If
    		Exit Function 
    	End If
    	
    	'Array
    	If IsArray(v1) Then
    		'Check dimension numbers and bounds
    		If Not ArrayBoundsEquals(v1, v2) Then
    			Equals=False
    			Exit Function			
    		End If
    		'Change the arrays to one dimension
    		Dim a1 As Variant, a2 As Variant
    		a1=ArrayToOneDimension(v1)
    		a2=ArrayToOneDimension(v2)
    		Dim i As Integer
    		For i=LBound(a1) To UBound(a1)
    			If Not Equals(a1(i), a2(i)) Then
    				Equals=False
    				Exit Function				
    			End If
    		Next
    		
    		Equals=True 
    		Exit Function		
    	End If
    
    	'List
    	If IsList(v1) Then
    		Dim tag As String		
    		ForAll e In v1
    			tag=ListTag(e)
    			If Not IsElement(v2(tag)) Then
    				Equals=False
    				Exit Function
    			ElseIf Not Equals(e, v2(tag)) Then
    				Equals=False
    				Exit Function				
    			End If
    		End ForAll
    		
    		Equals=True 
    		Exit Function		
    	End If
    	
    NotEquals:
    	Equals=False
    End Function
    
    Private Function DataType4Equals(v As Variant) As Integer
    	Dim result As Integer
    	result=DataType(v) 
    	Select Case result
    		Case V_BYTE, V_INTEGER, V_LONG, V_SINGLE, V_DOUBLE, V_CURRENCY
    			result=V_CURRENCY
    		Case Is > 8704 'Dynamic array
    			result=8704
    		Case Is > 8192 'Fixed array
    			result=8192
    		Case Is > 2048 'List
    			result=2048
    	End Select 
    	DataType4Equals=result
    End Function

    上面两个函数合在一起能比較随意两个变体型是否相等。对单值。比較值的相等性。

    对数组和列表,依次比較每个元素的相等性。对对象。假设该类型的对象定义了IsEqualTo方法,则调用该方法,否则比較引用的相等性。Null、Empty的比較已被覆盖。

    不同精度的数值型之间的转换也已考虑。

  • 相关阅读:
    python获取DBLP数据集
    GNUPLOT 画多组柱状图 以及 折线图 以及各种问题的解决方案
    Leetcode 1:two sum
    测试面试之如何测试一个杯子
    C++小总结
    统计‘1’的个数
    C语言小总结
    剑指offer面试题1---赋值运算符函数
    黑盒测试与白盒测试
    软件测试的原则
  • 原文地址:https://www.cnblogs.com/clnchanpin/p/6734708.html
Copyright © 2011-2022 走看看