我已经使用Access一段时间了,虽然我理解一个功能对Sub的明显好处,但是它可以返回值,因此我不确定为什么我应该使用功能上的子功能。毕竟,除非我弄错了;函数可以完成Subs所能做的一切吗?
注意:我完全知道如何使用Sub和Function,所以不要寻找它们如何工作的解释。
答案 0 :(得分:11)
就性能而言,这不会是任何重大问题。
主要区别在于用户定义的函数可以在代码中用于表达式,而子代码则不能。
这真是一个巨大的珠穆朗玛峰,在这里有所不同。
这种差异实际上并不局限于Access,但往往适用于我能想到的支持创建用户定义函数的每种编程语言和系统。
使用已定义函数的主要优点是很多,但最基本的问题是这样的函数可以在EXPRESSIONS中使用。
例如,在表单上按钮的单击设置中,通常可以将单个VBA [事件代码]例程附加到该按钮。
但是,您也可以在属性表中放置一个表达式,如下所示:
=MyUserFunction()
上面是一个方便的提示,从那以后你可以突出显示表单上的10个控件,并输入上面的表达式,你只需将上述功能分配给这10个按钮。你不能用sub。
做上面的事情另一个显着的区别是您可以将一个函数用作表单或报表上文本框的数据源(表达式)(同样,您不能使用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代码中作为表达式,而且ALSO可以用得足够惊人,这种能力包括SQL。
所以即使在代码中,你也可以去:
If MyCustomfucntion(SomeVar) = lngTestValue then
再次在上面,您不能在VBA表达式中使用sub。
更有趣的是,在Access中使用自定义XML作为功能区时,如果对“on action”属性使用function()表达式,则可以避免使用功能区回调。更好的是功能区将调用当前形式的那些函数(),而不是像你必须使用功能区回调那样的公共代码模块。
我可能会在另外10个页面上输入差异,但我认为这将开始是多余的,我不希望在这里以任何方式出现凝聚。
因此,VBA中的子函数与函数之间或大多数编程语言中的基本区别是完全相同的。
在Access中使用函数或几乎任何编程语言的好处也大致相同。例如,我可以在t-sql(标量)中定义用户定义的函数 - 然后您可以在任何t-sql代码中自由使用该t-sql函数,甚至可以在sql server中创建和使用该qu-sql函数。
所以这是一个子函数和一个函数之间的基本和简单的区别,我敢说那些编写过计算机代码的人几乎可以在任何编程语言中立即实现子程序和函数之间的上述重要和有用的区别。
答案 1 :(得分:8)
主要区别不仅在于返回值,似乎subs比函数更快 (至少在.net中)因为当没有返回值时,subs的MSIL代码要短得多。所以当没有返回值时,整体潜艇会更快。 哦,我刚刚找到了一个很好的来源(谈论.net),也许你想进一步阅读它 - Functions vs. Subroutines
答案 2 :(得分:1)
是的,函数只是一个返回值的Sub。
答案 3 :(得分:1)
我并不完全确定,但是,我认为subs比函数更快,因为子例程的变量是在创建子例程时定义的,并且可以通过引用内存位置来访问。函数必须在每次访问时分配内存空间。
子程序修改调用代码中的变量,函数保持原样不变。因此,子例程可以为调用代码提供几条经过修改的信息(与变量一样多的更改,包括数组),但函数一次只能为传递给它的值提供一个答案。由于存在这种差异,如果子程序中的变量不改变其值很重要,则必须将该值赋给子程序本身定义的临时变量。
答案 4 :(得分:1)
FWIW(我的理论;) -
让我们想一想真实的世界。
让我们说你想完成一些事情。有(至少)两种方法可以做到这一点。
首先,向帮助者发送信息请求,他们将返回给您的信息。所以你保持控制,即所有信息都流回你,你决定下一步该做什么。这更像是集中控制的环境。这是vba中“函数”的本质
第二种方式,将工作分成不同的任务,并为你的助手分配责任,为你完成任务,即辅助人员在这里执行实际工作,而不仅仅是收集信息。这是vba中'sub'的本质。
所以想想如果代码中断怎么办。通过函数调用,您可以专注于中心命令以查找失败原因。通过子调用,您必须遇到每个子工作并找出他们做错了什么。
当然,你可以搞砸了目的,并且功能可以正常工作,但只是获取信息,但当事情破裂时,这真的会让人感到困惑!哦,但你不能这样做,请阅读此链接 - http://www.cpearson.com/excel/differen.htm,其中指出Excel禁止更改单元格值的函数和从单元格调用的子函数。
答案 5 :(得分:0)
你会注意到事件总是潜艇,从不起作用。但是,在MS Access中,当您希望将它们用作事件的属性时,创建函数会很有用:
On Close: = MyCloseFunction()
Subs可以返回值ByRef。
答案 6 :(得分:0)
我发现了另一个差异,至少在Excel上,但在其他Office应用程序上也是如此。如果要通过添加按钮来启动VB程序来自定义功能区,则在“选择命令来源”下拉菜单中选择“宏”时,它将列出代码中的所有“子项”,但不列出“功能”。请注意,自定义功能区选择还将隐藏“私人小组”,而“公共职能”也会被隐藏。
因此,总而言之,这些将可作为功能区上的按钮添加: 子,公共子
这些将无法添加: 功能,公共功能,私有功能,私有子