Итак, мне было интересно, как я могу вернуть несколько значений из функции, подпрограммы или типа в VBA? У меня есть этот основной модуль, который должен собирать данные из нескольких функций, но функция может возвращать только одно значение. Итак, как я могу вернуть несколько единиц в сабвуфер?
Вернуть несколько значений из функции, подпрограммы или типа?
Ответы (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
Вы можете попробовать вернуть коллекцию 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
Имеет ли это смысл?
Идеи:
- Использовать передачу по ссылке (ByRef)
- Создайте тип, определяемый пользователем, для хранения материалов, которые вы хотите вернуть, и верните их.
- Аналогично 2 - создайте класс для представления возвращаемой информации и возвращайте объекты этого класса...
Вы также можете использовать вариантный массив в качестве возвращаемого результата, чтобы вернуть последовательность произвольных значений:
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
Некрасиво и чревато ошибками, потому что ваш вызывающий объект должен знать, что возвращается, чтобы использовать результат, но, тем не менее, иногда полезно.
Функция возвращает одно значение, но может "выводить" любое количество значений. Пример кода:
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 или более значений функции в 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
Не элегантно, но если вы не используете свой метод с перекрытием, вы также можете использовать глобальные переменные, определенные оператором Public в начале вашего кода, перед Subs. Однако вы должны быть осторожны, как только вы измените общедоступное значение, оно будет храниться в вашем коде во всех подпрограммах и функциях.
Я всегда подхожу к возврату более одного результата функции, всегда возвращая 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
вы можете соединить все данные, которые вам нужны из файла, в одну строку, а на листе 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