Вернуть несколько значений из функции, подпрограммы или типа?

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


person Kenny Bones    schedule 17.03.2011    source источник


Ответы (9)


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

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

' 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
person Michael Paulukonis    schedule 17.03.2011
comment
Я пытаюсь вернуть значения нескольких настроек, хранящихся в файле INI. Я мог бы написать по одной функции для каждого из них, но подумал, что лучше создать одну. Или более эффективным. Хотя не уверен, что это было бы. - person Kenny Bones; 17.03.2011
comment
Вы думаете неправильно. Метод возвращает одну вещь. Является ли это атомарным значением (32, c:\root, true и т. д.) или объектом, содержащим несколько значений ({width: 32, path: C:\root, promptForOverwrite: true}). Вы программист — вам нужно думать об этих вещах и соответствующим образом разрабатывать свое приложение. - person Michael Paulukonis; 17.03.2011
comment
Я дизайнер и общий IT-техник, и я просто пытаюсь научиться программировать. VBA появился из-за приложений Microsoft Office, и есть вещи, о которых я еще не знаю. Значения, которые я пытаюсь вернуть, - это просто основные строковые значения из файла INI. Ничего необычного или чего-то еще, и они также могут быть возвращены как строки. - person Kenny Bones; 17.03.2011
comment
Извините, это был плохо сформулированный комментарий. Строки или что-то еще, вы можете вернуть только одну вещь. Вещь может быть одной строкой или объектом, содержащим несколько свойств, которые сами являются строками. Но вы не можете вернуть несколько Вещей. - person Michael Paulukonis; 17.03.2011
comment
Ага! Теперь все становится яснее :) Хорошо, тогда мне нужно создать объект, который содержит несколько значений, верно? Будет ли это означать создание класса, содержащего их? Я не уверен, сколько значений мне нужно вернуть, это может быть всего несколько. Но в зависимости от того, как это получится, мне также может понадобиться хранить множество значений. Поэтому мне, вероятно, следует создать систему, которая справилась бы с этим. - person Kenny Bones; 17.03.2011
comment
Изучение классов коллекций VBA. Но не стройте его, пока он вам не понадобится. Будь проще. Моя самая большая проблема, когда я начал программировать, заключалась в попытке учесть возможности, которые никогда не происходили. Я потратил много времени, пытаясь решить проблемы, которых не было. - person Michael Paulukonis; 17.03.2011
comment
Только что попробовал, и это работает :) Фантастика! Теперь у меня есть ощущение, что я на самом деле делаю это правильно, а не каким-то прямым, легко сворачиваемым способом. - person Kenny Bones; 18.03.2011
comment
@KennyBones - когда я сказал, что вы программист - вам нужно подумать об этих вещах, которые не были предназначены, поскольку сейчас это выглядит как унижение. Вы все еще можете идентифицировать себя как дизайнера, но как только вы начнете программировать: бац! ты программист! Вы все еще на SO, так что похоже, что это работает. Поздравляю! - person Michael Paulukonis; 31.01.2014
comment
@photonic - это не работает для вас. С какой ошибкой вы сталкиваетесь? - person Michael Paulukonis; 02.09.2015
comment
Пользовательский тип не определяет @MichaelPaulukonis - person Photonic; 03.09.2015
comment
@Photonic - почему бы вам не открыть для этого новый выпуск? У вас другая проблема - что-то с объявлением определяемого пользователем типа (UDT). - person Michael Paulukonis; 03.09.2015
comment
Это чертовски здорово! - person Charles Wood; 05.05.2017
comment
Является ли это эквивалентом перечислений Java/С++? - person gimmegimme; 24.08.2018

Вы можете попробовать вернуть коллекцию VBA.

Пока вы имеете дело с парными значениями, такими как «Версия = 1.31», вы можете сохранить идентификатор как ключ («Версия»), а фактическое значение (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

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

person Oneide    schedule 17.03.2011

Идеи:

  1. Использовать передачу по ссылке (ByRef)
  2. Создайте тип, определяемый пользователем, для хранения материалов, которые вы хотите вернуть, и верните их.
  3. Аналогично 2 - создайте класс для представления возвращаемой информации и возвращайте объекты этого класса...
person Martin Milan    schedule 17.03.2011
comment
У вас есть примеры второй идеи? Я думаю, это было бы то, что мне нужно. - person Kenny Bones; 17.03.2011
comment
@ Кенни, посмотри справку по оператору «Тип». Это должно помочь вам начать. - person jtolle; 17.03.2011

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

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

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

person dlm    schedule 20.09.2013

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

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
person Givi    schedule 22.04.2014

вы можете вернуть 2 или более значений функции в VBA или любом другом визуальном базовом материале, но вам нужно использовать метод указателя, называемый 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
person Drl Sherif Omran    schedule 07.05.2015

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

person robotik    schedule 10.10.2013

Я всегда подхожу к возврату более одного результата функции, всегда возвращая 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
person SilverShotBee    schedule 02.08.2016

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