学习Excel技术,关注微信公众号:

excelperfect

在前面的几篇文章中,我们自定义的函数使用定义为Range的参数来从Excel工作表中获取数据,例如:

Function VINTERPOLATEB(Lookup_Value As Variant, _

Table_Array As Range, _

Col_Num As Long)

如果在公式中使用单元格区域作为参数来调用该函数,运转得非常好:

=VINTERPOLATEB($H1,$A$1:$C$10000,2)

但是,如果使用计算表达式或者一组常量作为参数,则返回的结果为#Value:

{=VINTERPOLATEB($H1,($A$1:$C$10000*1),2)}

这个公式是数组公式,因此输入完后按Ctrl+Shift+Enter组合键,Excel自动在公式两边添加花括号。

=VINTERPOLATEB(4.5,{1,3,3.5;4,4,4.5;5,4.5,5},2)

这个公式使用了3行3列的数组常量。

Excel在调用函数之前会检测到这些参数不是单元格区域。

通过将参数定义为Variant型而不是Range可以解决此问题:Variant型参数几乎可以包含任何内容!但用户自定义函数现在必须处理Variant可能包含的所有不同类型的数据。

一种简单的方法是将参数声明为Variant型变量:这会将所有内容强制转换为值:

Function TestFunc(theParameter AsVariant)

Dim vArr As Variant

vArr = theParameter

TestFunc = vArr

End Function

在VBE中,在赋值给函数的返回值的语句行设置断点,如下图1所示

图1

输入数组公式:

=TestFunc($A$1:$A$5*1)

本地窗口显示如下图2所示。

图2

在本地窗口可以看到,vArr变量包含2维Variant型数组,子类型为Double。

输入公式:

=TestFunc({1,2,3;5,6,7})

在本地窗口中可以看到其结果也是2维数组:

图3

输入公式:

=TestFunc({1,2,3})

在本地窗口可以看到结果为1维数组:

图4

输入公式:

=TestFunc({1;2;3})

在本地窗口可以看到结果为2维数组:

图5

输入公式:

=TestFunc(15)

可以看到结果为一个标量,而非数组:

图6

如果提供单元格区域作为函数参数:

=TestFunc($A$1:$A$5)

则得到:

图7

注意,theParameter变量包含对象子类型Range,意味着必须将它视为Range变量,而vArr包含从该Range变量中提取的值。

因此,在通用目的的用户自定义函数中,希望使用Variant型参数,并且经常需要确定变体的类型以及上限和下限。

为了获得最大效率,不能只使用vArr=theVariant,因为:

  • 不能使用.Value2,因为它可能不是单元格区域。

  • 在许多情况下,希望在强制转换所有值之前操控Range对象或者操控Range对象而不是强制转换所有值。

因此,这里有一个函数用来确定传递的内容以及它的大小:

Function Variant_Type(theVariantAs Variant)

Dim jRowL As Long

Dim jRowU As Long

Dim jColL As Long

Dim jColU As Long

Dim jType As Long

Dim varr As Variant

'

' theVariant可以包含标量, 数组, 或单元格区域

' 找到上限和下限以及类型

'type=1:单元格区域, 2:2维variant数组,

' 3:1-维variant数组(列的单行), 4:标量

'

On Error GoTo FuncFail

jType = 0

jRowL = 0

jColL = 0

jRowU = -1

jColU = -1

If TypeName(theVariant) = "Range" Then

jRowL = 1

jColL = 1

jRowU = theVariant.Rows.Count

jColU = theVariant.Columns.Count

jType = 1

ElseIf IsArray(theVariant) Then

jRowL = LBound(theVariant, 1)

jRowU = UBound(theVariant, 1)

On Error Resume Next

jColL = LBound(theVariant, 2)

jColU = UBound(theVariant, 2)

On Error GoTo FuncFail

If jColU < 0 Then

jType = 3

jColL = jRowL

jColU = jRowU

jRowL = 0

jRowU = -1

Else

jType = 2

End If

Else

jRowL = 1

jRowU = 1

jColL = 1

jColU = 1

jType = 4

End If

Variant_Type = jType

Exit Function

FuncFail:

Variant_Type = CVErr(xlErrValue)

jType = 0

jRowU = -1

jColU = -1

End Function

注意,首先测试变量是否包含Range,这是为了避免无意中将Range强制转换为其值。在确定变体的子类型时,VBA还有几种方法:

  • If TypeOf theVariant Is Range Then

  • If TypeName(theVariant) = “Range”Then

尝试使用VarType(theVariant)时要特别小心,这会对Range的覆盖范围进行强制转换,然后抛出结果值!

代码的图片版:

小结:在通用目的的用户自定义函数中,必须使用Variant类型的参数而不是Range类型。可以通过在处理变量之前确定变体包含的内容来有效地处理出现的问题。

必须声明标量变量_Excel VBA解读(136): 在用户定义函数中的变体、引用、数组、计算表达式、标量...相关推荐

  1. SQL Prompt数据库教程:标量用户定义函数误用作常量

    SQL Prompt是一款实用的SQL语法提示工具.SQL Prompt根据数据库的对象名称.语法和代码片段自动进行检索,为用户提供合适的代码选择.自动脚本设置使代码简单易读–当开发者不大熟悉脚本时尤 ...

  2. navicat存储过程返回值为空_Excel VBA解读(128):Function过程详解——枯燥的语法...

    学习Excel技术,关注微信公众号: excelperfect 在<Excel VBA解读(27):看看VBA的Sub过程和Function过程>中,我们讲解了Function过程的基本形 ...

  3. resize函数_Excel VBA解读(134): 使用Excel函数提高自定义函数的效率

    学习Excel技术,关注微信公众号: excelperfect 在上篇文章中,我们展示了自定义函数有效的方式是通过将单元格区域读取到Variant型数组来传递单元格区域数据.本文将介绍在自定义函数中最 ...

  4. redirect通过url_for传递参数_Excel VBA解读 | 进阶篇(127):Sub过程的参数传递技术...

    学习Excel技术,关注微信公众号: excelperfect 前面用了几篇文章详细讲解了Sub过程的语法及相关知识,本文进一步讲解与Sub过程相关的一些"重要事项",以进一步理解 ...

  5. jmeter中变量的作用范围_Jmeter里的用户定义变量和用户参数区别是什么?

    在一次导游平台的项目中,初始调试脚本阶段,我将需要一些参数都写死放在用户定义变量中. 就是下图这个东西,重点注意timestamp这个参数 脚本调试通过后,做并发调试,发现每次请求的参数值,times ...

  6. vba复制整个sheet内容_Excel VBA解读(74):移动或复制工作表——Move方法和Copy方法...

    有时候,我们可能想复制工作表,保留一份工作表的副本,以免误操作打乱工作表后无法恢复.有时候,我们也可能想移动工作表,调整工作表顺序,将工作表重新排列,以方便工作表的布置.本文介绍在VBA中实现这两种操 ...

  7. workbook对象需要关闭_Excel VBA解读(92):Workbook对象的Open事件和BeforeClose事件

    本文详细讲解Workbook对象常用的两个事件:Open事件和BeforeClose事件. Workbook_Open事件 当打开工作簿时发生Workbook_Open事件. 在ThisWorkboo ...

  8. SQL SERVER中用户定义标量函数(scalar user defined function)的性能问题

    SQL SERVER中用户定义标量函数(scalar user defined function)的性能问题 原文:SQL SERVER中用户定义标量函数(scalar user defined fu ...

  9. python中变量不需要事先声明_python 变量搜寻顺序法则LEGB之E注意事项

    众所周知,在python中,变量不需要事先声明,赋值后,即可调用使用.而调用的法则遵从LEGB法则,其中L为local,E为enclosing,G为Global,B为built-in,即变量首先在局部 ...

最新文章

  1. 去除Office 2010的右键“共享文件夹同步”菜单
  2. jquery插件---自动补全类插件
  3. Android之怎么隐藏EditText光标和自动显示键盘
  4. Hibernate_1_配置文件详解_基础案例_Hibernate工具类_API详解_持久化类编写规则
  5. c语言中的运算符按位或,|按位或运算符
  6. asp.net 读取mysql_asp.net封装mysql工具类,在页面上引用读取的数据
  7. 现场操作前,软件界面的各个功能面板应该通过拖动进行合理布局.请看参考图
  8. MATLAB局部放大
  9. 虚拟机opnsense作为dhcp服务器,ESXI 与 OPNSense 配合
  10. gitbub.com设置协作者提交代码步骤
  11. 撰写SCI论文的选题思路与技巧 - 易智编译EaseEditing
  12. log4jjavasciprt弹窗拦截
  13. python中py是什么意思_python中__init__.py是干什么的
  14. html转换到pdf转换器,HTML转换到PDF转换器
  15. cf1292 C. Xenon's Attack on the Gangs
  16. python批量剪辑音频pydub
  17. 【Hive】快速入门~
  18. Word中将一级标题设置为段前一行与段后一行时,不显示段前一行怎么办?
  19. 动画函数封装 —— 筋头云图案跟随鼠标移动
  20. 地平线发布AI on Horizon战略,与首汽约车、禾赛科技分别达成战略合作 | 2019上海车展...

热门文章

  1. oracle12c 删除pdb用户,oracle 12c pdb测试:创建、开关、删除
  2. 首款搭载鸿蒙os的设备,华为发布会配件汇总,首款搭载 鸿蒙OS 的设备来了
  3. scala mysql连接池_Java与Scala的两种简易版连接池
  4. 关于 m1 xcode12 编译报错 this target. for architecture arm64等问题解决方案
  5. Java instanceof关键字详解
  6. Java Double类详解
  7. 李航《统计学习方法》之HMM隐马尔可夫模型
  8. cv2.imread()返回none时应如何解决
  9. 数据挖掘初次接触!学习代码
  10. getline()函数