从函数、子函数或类型返回多个值?

发布于 2024-10-23 13:48:56 字数 95 浏览 8 评论 0原文

所以我想知道,如何从 VBA 中的函数、子函数或类型返回多个值? 我有这个主子程序,它应该从多个函数收集数据,但一个函数似乎只能返回一个值。那么我怎样才能将多个返回给一个子呢?

So I was wondering, how can I return multiple values from a function, sub or type in VBA?
I've got this main sub which is supposed to collect data from several functions, but a function can only return one value it seems. So how can I return multiple ones to a sub?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

野稚 2024-10-30 13:48:56

如果您真的非常希望一种方法返回多个值,您可能需要重新考虑应用程序的结构。

要么将事物分开,以便不同的方法返回不同的值,要么找出逻辑分组并构建一个对象来保存可以依次返回的数据。

' this is the VB6/VBA equivalent of a struct
' data, no methods
Private Type settings
    root As String
    path As String
    name_first As String
    name_last As String
    overwrite_prompt As Boolean
End Type


Public Sub Main()

    Dim mySettings As settings
    mySettings = getSettings()


End Sub

' if you want this to be public, you're better off with a class instead of a User-Defined-Type (UDT)
Private Function getSettings() As settings

    Dim sets As settings

    With sets ' retrieve values here
        .root = "foo"
        .path = "bar"
        .name_first = "Don"
        .name_last = "Knuth"
        .overwrite_prompt = False
    End With

    ' return a single struct, vb6/vba-style
    getSettings = sets

End Function

You might want want to rethink the structure of you application, if you really, really want one method to return multiple values.

Either break things apart, so distinct methods return distinct values, or figure out a logical grouping and build an object to hold that data that can in turn be returned.

' this is the VB6/VBA equivalent of a struct
' data, no methods
Private Type settings
    root As String
    path As String
    name_first As String
    name_last As String
    overwrite_prompt As Boolean
End Type


Public Sub Main()

    Dim mySettings As settings
    mySettings = getSettings()


End Sub

' if you want this to be public, you're better off with a class instead of a User-Defined-Type (UDT)
Private Function getSettings() As settings

    Dim sets As settings

    With sets ' retrieve values here
        .root = "foo"
        .path = "bar"
        .name_first = "Don"
        .name_last = "Knuth"
        .overwrite_prompt = False
    End With

    ' return a single struct, vb6/vba-style
    getSettings = sets

End Function
不知在何时 2024-10-30 13:48:56

您可以尝试返回 VBA 集合。

只要您处理对值,例如“Version=1.31”,您就可以将标识符存储为键(“Version”),并将实际值(1.31)存储为项目本身。

Dim c As New Collection
Dim item as Variant
Dim key as String
key = "Version"
item = 1.31
c.Add item, key
'Then return c

之后访问这些值就轻而易举了:

c.Item("Version") 'Returns 1.31
or
c("Version") '.Item is the default member

这有意义吗?

You could try returning a VBA Collection.

As long as you dealing with pair values, like "Version=1.31", you could store the identifier as a key ("Version") and the actual value (1.31) as the item itself.

Dim c As New Collection
Dim item as Variant
Dim key as String
key = "Version"
item = 1.31
c.Add item, key
'Then return c

Accessing the values after that it's a breeze:

c.Item("Version") 'Returns 1.31
or
c("Version") '.Item is the default member

Does it make sense?

薄荷→糖丶微凉 2024-10-30 13:48:56

想法:

  1. 使用引用传递(ByRef)
  2. 构建一个用户定义类型来保存您想要返回的内容,然后返回它。
  3. 类似于2 - 构建一个类来表示返回的信息,并返回该类的对象...

Ideas :

  1. Use pass by reference (ByRef)
  2. Build a User Defined Type to hold the stuff you want to return, and return that.
  3. Similar to 2 - build a class to represent the information returned, and return objects of that class...
梦醒灬来后我 2024-10-30 13:48:56

您还可以使用变体数组作为返回结果来返回任意值的序列:

Function f(i As Integer, s As String) As Variant()
    f = Array(i + 1, "ate my " + s, Array(1#, 2#, 3#))
End Function

Sub test()
    result = f(2, "hat")
    i1 = result(0)
    s1 = result(1)
    a1 = result(2)
End Sub

丑陋且容易出现错误,因为调用者需要知道返回的内容才能使用结果,但有时还是有用的。

You can also use a variant array as the return result to return a sequence of arbitrary values:

Function f(i As Integer, s As String) As Variant()
    f = Array(i + 1, "ate my " + s, Array(1#, 2#, 3#))
End Function

Sub test()
    result = f(2, "hat")
    i1 = result(0)
    s1 = result(1)
    a1 = result(2)
End Sub

Ugly and bug prone because your caller needs to know what's being returned to use the result, but occasionally useful nonetheless.

枫林﹌晚霞¤ 2024-10-30 13:48:56

函数返回一个值,但它可以“输出”任意数量的值。示例代码:

Function Test (ByVal Input1 As Integer, ByVal Input2 As Integer, _
ByRef Output1 As Integer, ByRef Output2 As Integer) As Integer

  Output1 = Input1 + Input2
  Output2 = Input1 - Input2
  Test = Output1 + Output2

End Function

Sub Test2()

  Dim Ret As Integer, Input1 As Integer, Input2 As Integer, _
  Output1 As integer, Output2 As Integer
  Input1 = 1
  Input2 = 2
  Ret = Test(Input1, Input2, Output1, Output2)
  Sheet1.Range("A1") = Ret     ' 2
  Sheet1.Range("A2") = Output1 ' 3
  Sheet1.Range("A3") = Output2 '-1

End Sub

A function returns one value, but it can "output" any number of values. A sample code:

Function Test (ByVal Input1 As Integer, ByVal Input2 As Integer, _
ByRef Output1 As Integer, ByRef Output2 As Integer) As Integer

  Output1 = Input1 + Input2
  Output2 = Input1 - Input2
  Test = Output1 + Output2

End Function

Sub Test2()

  Dim Ret As Integer, Input1 As Integer, Input2 As Integer, _
  Output1 As integer, Output2 As Integer
  Input1 = 1
  Input2 = 2
  Ret = Test(Input1, Input2, Output1, Output2)
  Sheet1.Range("A1") = Ret     ' 2
  Sheet1.Range("A2") = Output1 ' 3
  Sheet1.Range("A3") = Output2 '-1

End Sub
や莫失莫忘 2024-10-30 13:48:56

您可以将 2 个或更多值返回给 VBA 或任何其他 Visual Basic 内容中的函数,但您需要使用称为 Byref 的指针方法。请参阅下面我的示例。我将创建一个函数来添加和减去 2 个值,例如 5,6

sub Macro1
    ' now you call the function this way
    dim o1 as integer, o2 as integer
    AddSubtract 5, 6, o1, o2
    msgbox o2
    msgbox o1
end sub


function AddSubtract(a as integer, b as integer, ByRef sum as integer, ByRef dif as integer)
    sum = a + b
    dif = b - 1
end function

you can return 2 or more values to a function in VBA or any other visual basic stuff but you need to use the pointer method called Byref. See my example below. I will make a function to add and subtract 2 values say 5,6

sub Macro1
    ' now you call the function this way
    dim o1 as integer, o2 as integer
    AddSubtract 5, 6, o1, o2
    msgbox o2
    msgbox o1
end sub


function AddSubtract(a as integer, b as integer, ByRef sum as integer, ByRef dif as integer)
    sum = a + b
    dif = b - 1
end function
听,心雨的声音 2024-10-30 13:48:56

不优雅,但如果您不重叠使用您的方法,您还可以使用全局变量,由代码开头的 Subs 之前的 Public 语句定义。
不过,您必须小心,一旦更改公共值,它将在所有子函数和函数的整个代码中保留。

Not elegant, but if you don't use your method overlappingly you can also use global variables, defined by the Public statement at the beginning of your code, before the Subs.
You have to be cautious though, once you change a public value, it will be held throughout your code in all Subs and Functions.

葮薆情 2024-10-30 13:48:56

我总是通过始终返回 ArrayList 来从函数返回多个结果。通过使用 ArrayList,我只能返回一项,其中包含许多多个值,混合在字符串和整数之间。

一旦我在主子中返回了 ArrayList,我只需使用 ArrayList.Item(i).ToString ,其中 i 是索引我想从 ArrayList 返回的值

一个例子:

 Public Function Set_Database_Path()
        Dim Result As ArrayList = New ArrayList
        Dim fd As OpenFileDialog = New OpenFileDialog()


        fd.Title = "Open File Dialog"
        fd.InitialDirectory = "C:\"
        fd.RestoreDirectory = True
        fd.Filter = "All files (*.*)|*.*|All files (*.*)|*.*"
        fd.FilterIndex = 2
        fd.Multiselect = False


        If fd.ShowDialog() = DialogResult.OK Then

            Dim Database_Location = Path.GetFullPath(fd.FileName)

            Dim Database_Connection_Var = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=""" & Database_Location & """"

            Result.Add(Database_Connection_Var)
            Result.Add(Database_Location)

            Return (Result)

        Else

            Return (Nothing)

        End If
    End Function

然后像这样调用函数:

Private Sub Main_Load()
  Dim PathArray As ArrayList

            PathArray = Set_Database_Path()
            My.Settings.Database_Connection_String = PathArray.Item(0).ToString
            My.Settings.FilePath = PathArray.Item(1).ToString
            My.Settings.Save()
End Sub

I always approach returning more than one result from a function by always returning an ArrayList. By using an ArrayList I can return only one item, consisting of many multiple values, mixing between Strings and Integers.

Once I have the ArrayList returned in my main sub, I simply use ArrayList.Item(i).ToString where i is the index of the value I want to return from the ArrayList

An example:

 Public Function Set_Database_Path()
        Dim Result As ArrayList = New ArrayList
        Dim fd As OpenFileDialog = New OpenFileDialog()


        fd.Title = "Open File Dialog"
        fd.InitialDirectory = "C:\"
        fd.RestoreDirectory = True
        fd.Filter = "All files (*.*)|*.*|All files (*.*)|*.*"
        fd.FilterIndex = 2
        fd.Multiselect = False


        If fd.ShowDialog() = DialogResult.OK Then

            Dim Database_Location = Path.GetFullPath(fd.FileName)

            Dim Database_Connection_Var = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=""" & Database_Location & """"

            Result.Add(Database_Connection_Var)
            Result.Add(Database_Location)

            Return (Result)

        Else

            Return (Nothing)

        End If
    End Function

And then call the Function like this:

Private Sub Main_Load()
  Dim PathArray As ArrayList

            PathArray = Set_Database_Path()
            My.Settings.Database_Connection_String = PathArray.Item(0).ToString
            My.Settings.FilePath = PathArray.Item(1).ToString
            My.Settings.Save()
End Sub
南渊 2024-10-30 13:48:56

您可以将文件中所需的所有数据连接到单个字符串,并在 Excel 工作表中将其与文本分隔开。
这是我针对同一问题所做的一个示例,请欣赏:

Sub CP()
Dim ToolFile As String

Cells(3, 2).Select

For i = 0 To 5
    r = ActiveCell.Row
    ToolFile = Cells(r, 7).Value
    On Error Resume Next
    ActiveCell.Value = CP_getdatta(ToolFile)

    'seperate data by "-"
    Selection.TextToColumns Destination:=Range("C3"), DataType:=xlDelimited, _
        TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=True, _
        Semicolon:=False, Comma:=False, Space:=False, Other:=True, OtherChar _
        :="-", FieldInfo:=Array(Array(1, 1), Array(2, 1)), TrailingMinusNumbers:=True

Cells(r + 1, 2).Select
Next


End Sub

Function CP_getdatta(ToolFile As String) As String
    Workbooks.Open Filename:=ToolFile, UpdateLinks:=False, ReadOnly:=True

    Range("A56000").Select
    Selection.End(xlUp).Select
    x = CStr(ActiveCell.Value)
    ActiveCell.Offset(0, 20).Select
    Selection.End(xlToLeft).Select
    While IsNumeric(ActiveCell.Value) = False
        ActiveCell.Offset(0, -1).Select
    Wend
    ' combine data to 1 string
    CP_getdatta = CStr(x & "-" & ActiveCell.Value)
    ActiveWindow.Close False

End Function

you could connect all the data you need from the file to a single string, and in the excel sheet seperate it with text to column.
here is an example i did for same issue, enjoy:

Sub CP()
Dim ToolFile As String

Cells(3, 2).Select

For i = 0 To 5
    r = ActiveCell.Row
    ToolFile = Cells(r, 7).Value
    On Error Resume Next
    ActiveCell.Value = CP_getdatta(ToolFile)

    'seperate data by "-"
    Selection.TextToColumns Destination:=Range("C3"), DataType:=xlDelimited, _
        TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=True, _
        Semicolon:=False, Comma:=False, Space:=False, Other:=True, OtherChar _
        :="-", FieldInfo:=Array(Array(1, 1), Array(2, 1)), TrailingMinusNumbers:=True

Cells(r + 1, 2).Select
Next


End Sub

Function CP_getdatta(ToolFile As String) As String
    Workbooks.Open Filename:=ToolFile, UpdateLinks:=False, ReadOnly:=True

    Range("A56000").Select
    Selection.End(xlUp).Select
    x = CStr(ActiveCell.Value)
    ActiveCell.Offset(0, 20).Select
    Selection.End(xlToLeft).Select
    While IsNumeric(ActiveCell.Value) = False
        ActiveCell.Offset(0, -1).Select
    Wend
    ' combine data to 1 string
    CP_getdatta = CStr(x & "-" & ActiveCell.Value)
    ActiveWindow.Close False

End Function
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文