17

我已经使用 Access 有一段时间了,虽然我理解函数相对于 Sub 的明显好处,因为它可以返回值,但我不确定为什么我应该使用 Sub一个函数。毕竟,除非我弄错了;函数可以做所有 Subs 可以做的事情吗?

注意:我完全知道如何同时使用 Sub 和 Function,所以不需要解释它们是如何工作的。

4

7 回答 7

19

就性能而言,这在这里不会是任何重大问题。

主要区别在于用户定义的函数可以在代码中的表达式中使用,而 sub 不能。

这真的是一个巨大的珠穆朗玛峰。

这种差异并不仅限于 Access,而是适用于我能想到的所有支持创建用户定义函数的编程语言和系统。

使用定义函数的主要优势有很多,但最基本的问题是这样的函数可以在 EXPRESSIONS 中使用。

例如,在表单上按钮的单击设置中,您通常可以将单个 VBA [事件代码] 例程附加到该按钮。

但是,您也可以在属性表中放置一个表达式,如下所示:

=MyUserFunction()

以上是一个方便的提示,从那时起,您可以突出显示表单上的 10 个控件,然后输入上面的表达式,然后将上述功能分配给这 10 个按钮。你不能用一个子做上述事情。

另一个显着的区别是您可以将函数用作表单或报表上文本框的数据源(表达式)(同样,您不能使用 sub 执行此操作)。

另一个显着的区别是您可以在 SQL 中使用这些函数。这是一种真正奇妙的能力,因为这样您就可以为查询的每一行“运行”代码。这意味着您可以扩展 SQL 的能力和功能。

您甚至可以使用这个想法在 sql 查询中显示 VBA 变量,因为您只需构建一个返回 VBA 变量的公共函数,这可以在查询中使用 - 但是您不能在查询中使用 VBA 变量!

而这种 SQL 的扩展开辟了无穷无尽的想法:

所以我可以构建一个名为 ToMorrow() 的公共函数

Public Function Tomorrow() as date

   Tomorrow() = date() + 1

End Function.

现在在查询生成器中,我可以去:

Select FirstName, lastName, Tomorrow() as NextDay from tblCustomers

您甚至可以进行自定义转换,例如:

Select FirstName, LastName, Celsius([DailyGreenHouseTemp]) from tblGreenHouse.

上面的每日温度读数可以以华氏度为单位,您只需定义一个名为 Celsius 的公共函数,如下所示:

Public Function Celsius(Temperature As Variant) As Variant

   Celsius = (Temperature * 1.8) + 32

End Function

现在,虽然上述功能很简单,但它可以执行复杂的记录集处理复杂的算法,以根据温度和湿度确定花盆上方的湿度。

因此,一旦我们定义了这样一个公共函数,那么关键概念就是这样一个函数不仅可以在 VBA 代码中用作表达式,而且还可以令人惊奇地使用这种能力,包括 SQL。

所以即使在代码中,你也可以去:

If MyCustomfucntion(SomeVar) = lngTestValue then

同样在上面,您不能在 VBA 表达式中使用 sub。

更有趣的是,在 Access 中为功能区使用自定义 XML 时,如果您对“on action”属性使用 function() 表达式,则可以避免功能区回调的需要。更好的是功能区将以当前形式调用这些函数(),而不是像您必须使用功能区回调那样的公共代码模块。

关于差异,我可能可以再输入 10 多页,但我认为这将开始是多余的,我不想在这里以任何方式出现浓缩。

因此,在 VBA 中或实际上在大多数编程语言中,子和函数之间的基本区别非常相似。

在 Access 或几乎任何编程语言中使用函数的好处也大致相同。例如,我可以在 t-sql(标量)中定义一个用户定义的函数——然后您可以在您的任何 t-sql 代码甚至是您为 sql server 创建和使用的查询中自由使用该 t-sql 函数。

所以这是子程序和函数之间的基本和简单的区别,我敢说那些用几乎任何编程语言编写过计算机代码的人都会立即意识到子程序和函数之间的上述重要和有用的区别。

于 2012-07-19T06:59:30.220 回答
13

主要区别不仅在于返回值,而且似乎 subs 比函数更快(至少在 .net 中),因为 subs 的 MSIL 代码在没有返回值时要短得多。因此,当没有返回值时,整体 subs 会更快。哦,我刚刚找到了一个很好的来源(谈论 .net),也许您想进一步了解它- 函数与子例程

于 2012-07-18T11:10:28.460 回答
1

是的,Function 只是一个返回值的 Sub。

于 2012-07-18T11:08:39.690 回答
1

但是,我不确定,我认为 subs 比函数更快,因为子例程的变量是在创建子例程时定义的,并且可以通过引用内存位置来访问。函数每次被访问时都必须分配内存空间。

子例程修改调用代码中的变量,函数保持它们不变。因此,子例程可以向调用代码提供几条修改后的信息(与变量一样多,包括数组),但函数一次只能为传递给它的值提供一个答案。由于这种差异,如果子程序中的变量不改变其值很重要,则必须将该值分配给子程序本身中定义的临时变量。

于 2015-11-03T19:56:37.817 回答
1

FWIW(我的理论;) -

让我们想想现实世界来理解这一点。

假设您想完成某事。有(至少)两种方法可以做到这一点。

第一种方式,向帮助者发送信息请求,他们会为您返回信息。所以你保持控制,即所有信息都流回给你,如果有的话,你正在决定下一步做什么。这更像是集中控制的环境。这是vba中“函数”的本质

第二种方式,将工作划分为单独的任务,并将责任分配给您的助手为您完成任务,即实际工作由助手执行,而不是仅收集信息。这是vba中'sub'的本质。

所以想想如果代码中断怎么办。通过函数调用,您可以专注于中央命令来寻找失败的原因。使用 sub 调用,您必须查看每个 sub 的工作并找出他们做错了什么。

当然,你可以搞砸目的,让函数正常工作,而 subs 只是获取信息,但是当事情破裂时,这真的会让人感到困惑!哦,但你不能这样做,请阅读此链接 - http://www.cpearson.com/excel/diferen.htm,其中指出 Excel 禁止更改单元格值的函数和从单元格调用的子程序。

于 2015-11-16T18:19:19.467 回答
0

你会注意到,事件总是 subs,从来没有函数。但是,在 MS Access 中,当您希望将函数用作事件的属性时,创建函数会很有用:

On Close: = MyCloseFunction()

Subs 可以返回一个值ByRef

于 2012-07-18T11:14:42.683 回答
0

我发现了另一个区别,至少在 Excel 上,但可能在其他 Office 应用程序上。如果您想通过添加按钮来启动 VB 程序来自定义功能区,当您在“选择命令来自”下拉菜单中选择宏时,它会列出代码中的所有子程序,但不列出函数。请注意,私人子也将从自定义功能区选择中隐藏,公共功能也是如此。

总而言之,这些可以作为按钮添加到功能区:Sub、Public Sub

并且这些将无法添加:Function、Public Function、Private Function、Private Sub

于 2020-02-18T16:34:08.037 回答