Вернуть несколько значений из функции, подпункта или типа? - PullRequest
31 голосов
/ 17 марта 2011

Так что мне было интересно, как я могу вернуть несколько значений из функции, подпункта или типа в VBA? У меня есть основная подпрограмма, которая должна собирать данные из нескольких функций, но функция может возвращать только одно значение, которое кажется. Итак, как я могу вернуть несколько к сабу?

Ответы [ 9 ]

49 голосов
/ 17 марта 2011

Возможно, вы захотите переосмыслить структуру вашего приложения, если вы действительно хотите, чтобы один метод возвращал несколько значений.

Либо разбивайте вещи на части, чтобы разные методы возвращали разные значения, либо определяйте логическую группировку и создавайте объект для хранения данных, которые, в свою очередь, могут быть возвращены.

' 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
20 голосов
/ 17 марта 2011

Вы можете попытаться вернуть коллекцию 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

Имеет ли это смысл?

13 голосов
/ 17 марта 2011

Идеи:

  1. Использование прохода по ссылке (ByRef)
  2. Создание пользовательского типа для хранения материала, который вы хотите вернуть, и возврата этого.
  3. Аналогично 2 - создать класс для представления возвращаемой информации и вернуть объекты этого класса ...
8 голосов
/ 21 сентября 2013

Вы также можете использовать вариантный массив в качестве возвращаемого результата, чтобы вернуть последовательность произвольных значений:

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

Уродливо и подвержено ошибкам, потому что вызывающая сторона должна знать, что возвращается для использования результата, ноТем не менее, иногда полезно.

4 голосов
/ 23 апреля 2014

Функция возвращает одно значение, но она может «вывести» любое количество значений. Пример кода:

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
2 голосов
/ 07 мая 2015

вы можете вернуть 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
2 голосов
/ 10 октября 2013

Не элегантно, но если вы не используете свой метод с наложением, вы также можете использовать глобальные переменные, определенные выражением Public в начале вашего кода, перед Subs.Однако вы должны быть осторожны, когда вы измените публичное значение, оно будет храниться во всем вашем коде во всех подсистемах и функциях.

1 голос
/ 02 августа 2016

Я всегда подхожу к возвращению более одного результата из функции, всегда возвращая ArrayList.Используя ArrayList, я могу вернуть только один элемент, состоящий из множества значений, смешивающихся между Strings и Integers.

Как только я получу 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
0 голосов
/ 09 декабря 2014

вы можете соединить все необходимые данные из файла в одну строку, а в листе 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
...