我是一个VBA(以及一般编程)专家。我试图理解VBA中子程序和函数之间的根本区别。我读过各种各样的网站/书籍,但没有一本能清楚地说明这些概念是什么以及它们之间的区别。
特别是,我看到到处都有这样的解释:;子执行任务但不返回值"0";但是";函数返回要执行的任务的值";。
嗯。。。因此,假设我编写了一个函数,它从Excel中的一个单元格中获取一个(数值)值,并返回该值的两倍(在另一个单元格)。我也可以写一个做同样事情的子:读取一个单元格的值,然后打印该值的两倍。那么,为什么它说sub不返回值,而它显然返回了值呢?!
请帮我理解这一点。
"返回";与";打印";。打印是向用户显示结果的过程;一般来说,程序不能使用打印值。另一方面,返回值是为了进一步处理;用户不能直接访问它。
与现实世界相比:子程序就像一个执行某个动作的命令;函数就像一个问题,给你一个可以进一步询问的答案。
想象一下,你是一家建筑公司的工头,但你讨厌离开办公室"在南墙上安装一扇窗户";是一个命令——一个子例程。一个工人出去做这件事;拍一张大楼的照片,并把它展示给客户;。工头没有从中得到任何信息(除了确认工人已经完成了你的要求)。
另一方面;大楼旁边的树有多高&"还有水泥吗&"询问客户关于这张照片的情况,并告诉我他的评论是什么;所有人都给工头一个答案,工头可以据此做出进一步的决定。这就是职能。
如果您有一个函数AreaOfRectangle
可以计算宽度乘以高度,那么您也可以有一个功能AreaOfRectangularBox
,它向AreaOfRectangle
询问长方体的前、左和顶面的面积,将它们分别加倍(因为后、右和底面相同),然后将它们相加,返回矩形长方体的面积。用户仍然不知道这个数字是多少,但程序知道。
如果你有一个子程序AreaOfRectangle
,它显示屏幕上的宽度乘以高度,你就不能在程序的其余部分使用这些知识,因为AreaOfRectangle
不会向程序返回任何信息(除了它是用它正在做的事情来完成的)。
在一些编程语言中,子例程有能力修改它们的参数,因此它并不是一成不变的,但仍然是"返回";(到呼叫代码)和";打印";(对用户)保持相关性。此外,在某些语言中,子例程甚至不必报告它们何时完成(这些被称为"异步");但这也是稍后要讨论的细节。
编辑:
返回值的两倍(在另一个单元格中)
类似Range("A2").Value = Range("A1").Value * 2
的东西不是";返回";。这是命令程序将值存储在单元格中——概念上接近子程序(在某些语言中,它可能是一个子例程——类似于SetAt(X, Y, Val)
——尽管VBA使用对.Value
属性的赋值)。程序稍后可以查询该单元格中的值——概念上接近函数(在某些语言中,它实际上可能是一个函数——类似于Val = GetAt(X, Y)
——尽管VBA使用对.Value
属性的简单访问)。
如果在单元格中的公式中使用函数的返回值,比如=DoubleThis(5)
,那么这实际上是正确的返回。但至关重要的是,这是一个公式,所以基本上它仍然在代码的领域,而不是用户的领域。您也可以写入=DoubleThis(5)+7
,并且10
的返回值将用于与7
相加,以获得17
的总结果。(然后Excel接管并显示单元格值;但这不再是您的代码。)
有时人们使用这个词有点随意;但如果你在学习编程,你必须严格区分这两种场景。
子与函数
- 请注意,以下尝试描述子函数和函数之间的差异时存在不准确和信息缺失
Sub
- 下面是一个简单的过程,返回
B1
中A1
值的两倍
Sub sDoubleSimple()
Range("B1").Value = 2 * Range("A1").Value
End Sub
- 要将其用于所选单元格,可以添加两个参数并重写过程:
Sub sDouble(ByVal SourceCell As Range, ByVal DestinationCell As Range)
DestinationCell.Value = 2 * SourceCell.Value
End Sub
- 要使用它,您可以通过以下方式调用它:
Sub sExamples()
sDouble Range("A1"), Range("B1")
sDouble Range("A2"), Range("B2")
Dim sCell As Range
For Each sCell In Range("A3:A10").Cells
sDouble2 Cells(sCell.Row, "B"), sCell
Next sCell
End Sub
- 基本上,它返回的值是列
B
中列A
的值的的两倍 - 请注意,我在前面相当不准确的描述中使用的返回不是与函数相关的返回
功能
- 要"将最后一个子函数重写为函数",您可以执行
Function fDouble(ByVal SourceCell As Range) As Double
fDouble = 2 * SourceCell.Value
End Function
并像这样使用它:
Sub fExamples()
Range("B1").Value = fDouble(Range("A1"))
Range("B2").Value = fDouble(Range("A2"))
Dim sCell As Range
For Each sCell In Range("A3:A10").Cells
Cells(sCell.Row, "B").Value = fDouble(sCell)
Next sCell
End Sub
乍一看,除了语法之外,"子方法和函数方法"之间似乎没有区别。他们实际上也做了同样的事情,但有很大的不同,比如看线。。。
Range("B1").Value = fDouble(Range("A1"))
我们可以看到
fDouble(Range("A1"))
将被写入Range("B1")
,因此我们可以得出结论,前者必须是函数的返回值的数字,即我们可以以各种方式使用它,在消息框中返回它。。。
Sub fExamplesMsg()
MsgBox fDouble(Range("A1"))
MsgBox fDouble(Range("A2"))
Dim sCell As Range
For Each sCell In Range("A3:A10").Cells
MsgBox fDouble(sCell)
Next sCell
End Sub
或在"立即"窗口中(Ctrl+G)。。。
Sub fExamplesPrint()
Debug.Print fDouble(Range("A1"))
Debug.Print fDouble(Range("A2"))
Dim sCell As Range
For Each sCell In Range("A3:A10").Cells
Debug.Print fDouble(sCell)
Next sCell
End Sub
- 最重要的是,我们可以将return值写入变量,例如在
If
语句中使用它来进一步选择单元格中将返回的
Sub fExamplesConditional()
Dim cValue As Double
cValue = fDouble(Range("A1"))
If cValue > 50 Then
Range("B1").Value = cValue
End If
cValue = fDouble(Range("A2"))
If cValue > 50 Then
Range("B2").Value = cValue
End If
Dim sCell As Range
For Each sCell In Range("A3:A10").Cells
cValue = fDouble(sCell.Value)
If cValue > 50 Then
Cells(sCell.Row, "B").Value = cValue
End If
Next sCell
End Sub
- 基本上,如果结果大于
50
,它将返回两倍于B
列中A
列值的
结论
- 您可以说子执行,而函数返回。函数将在调用过程中返回一个值,您可以在该过程中进一步操作它。想想所有Excel函数,它们都返回结果。它们不会将结果写入另一个单元格,而是写入该单元格,例如,在单元格
B1
中,可以使用=fDouble(A1)