87. 再谈变体型Variant
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的比較已被覆盖。
不同精度的数值型之间的转换也已考虑。
87. 再谈变体型Variant的更多相关文章
- mui初级入门教程(四)— 再谈webview,从小白变“大神”!
文章来源:小青年原创发布时间:2016-06-05关键词:mui,html5+,webview转载需标注本文原始地址: http://zhaomenghuan.github.io/#!/blog/20 ...
- 沉淀再出发:再谈java的多线程机制
沉淀再出发:再谈java的多线程机制 一.前言 自从我们学习了操作系统之后,对于其中的线程和进程就有了非常深刻的理解,但是,我们可能在C,C++语言之中尝试过这些机制,并且做过相应的实验,但是对于ja ...
- [转载]再谈百度:KPI、无人机,以及一个必须给父母看的案例
[转载]再谈百度:KPI.无人机,以及一个必须给父母看的案例 发表于 2016-03-15 | 0 Comments | 阅读次数 33 原文: 再谈百度:KPI.无人机,以及一个必须 ...
- Unity教程之再谈Unity中的优化技术
这是从 Unity教程之再谈Unity中的优化技术 这篇文章里提取出来的一部分,这篇文章让我学到了挺多可能我应该知道却还没知道的知识,写的挺好的 优化几何体 这一步主要是为了针对性能瓶颈中的”顶点 ...
- 浅谈HTTP中Get与Post的区别/HTTP协议与HTML表单(再谈GET与POST的区别)
HTTP协议与HTML表单(再谈GET与POST的区别) GET方式在request-line中传送数据:POST方式在request-line及request-body中均可以传送数据. http: ...
- Another Look at Events(再谈Events)
转载:http://www.qtcn.org/bbs/simple/?t31383.html Another Look at Events(再谈Events) 最近在学习Qt事件处理的时候发现一篇很不 ...
- 再谈DOMContentLoaded与渲染阻塞—分析html页面事件与资源加载
浏览器的多线程中,有的线程负责加载资源,有的线程负责执行脚本,有的线程负责渲染界面,有的线程负责轮询.监听用户事件. 这些线程,根据浏览器自身特点以及web标准等等,有的会被浏览器特意的阻塞.两个很明 ...
- 再谈HTTP2性能提升之背后原理—HTTP2历史解剖
即使千辛万苦,还是把网站升级到http2了,遇坑如<phpcms v9站http升级到https加http2遇到到坑>. 因为理论相比于 HTTP 1.x ,在同时兼容 HTTP/1.1 ...
- GoF设计模式三作者15年后再谈模式
Erich Gamma, Richard Helm, 和 Ralph Johnson在GoF设计模式发表15年以后,再谈模式,另外一位作者,也是四色原型的发明者Peter已经过世. 提问者:如今有85 ...
随机推荐
- 【BZOJ-3527】力 FFT
3527: [Zjoi2014]力 Time Limit: 30 Sec Memory Limit: 256 MBSec Special JudgeSubmit: 1544 Solved: 89 ...
- Linux性能监控分析命令(三)—iostat命令介绍
性能监控分析的命令包括如下: 1.vmstat 2.sar 3.iostat 4.top 5.free 6.uptime 7.netstat 8.ps 9.strace 10.lsof 命令介绍: i ...
- 网络服务器搭建的那些事(PV QPS Throughput) 转载
一.前言: 从事后台sever开发的同学,代码开发完成之后,上线之前,总会进行各种黑盒白盒测试,压测.正确性测试... 而测试同学,会给开发同学一份测试报告,需要开发同学进行确认...问题来了,里面好 ...
- 使用Chrome快速实现数据的抓取(四)——优点
些一个抓取WEB页面的数据程序比较简单,大多数语言都有相应的HTTP库,一个简单的请求响应即可,程序发送Http请求给Web服务器,服务器返回HTML文件.交互方式如下: 在使用DevProtocol ...
- C# 去掉webapi返回json所带的转义字符
反序列换报错: {"Error converting value \"{\"Result\":true,\"Code\":\"\& ...
- go test
testing 是go中自动测试的包, 直接import就可以使用, 使用时需要注意以下规范 执行测试函数的文件必须以 _test.go 结尾, 注意下划线 单元测试函数名必须以 Test 开头, 并 ...
- C#程序集系列12,C#编译器和CLR如何找寻程序集
本篇体验C#编译器和CLR运行时如何查找程序集,并自定义CLR运行时查找程序集的方式. □ C#编译器和CLR运行时如何查找程序集 C#编译器在哪里?--在C:\Windows\Microsoft.N ...
- error launching remote program failed to get the task for process
Error Starting executable: error launching remote program failed to get the task for process 715 这个 ...
- Python之“可变”的tuple
前面我们看到了tuple一旦创建就不能修改.现在,我们来看一个"可变"的tuple: >>> t = ('a', 'b', ['A', 'B']) 注意到 t 有 ...
- 算法:堆排序(Heap Sort)
备注 考虑到 Heap 的特性,很容易想到将其用作排序的用处,为了提高效率需要适当的改进一下,如:in place remove 和 in place move down. 代码 using Syst ...