【问题标题】:VBA Passing an array to a function and backVBA将数组传递给函数并返回
【发布时间】:2020-08-19 06:53:11
【问题描述】:

我已经开始复习 cpearson 关于传递和返回数组的文章,但我对细节有点迷失了。以下内容无效,并由论文确认。似乎我可以通过遍历数组以将每个元素设置为等于另一个数组中的元素来解决问题。如何使用函数执行此操作?

Sub test()

    Dim Arr() as Variant
    Dim CurrDoc as Word.Document

    ReDim Arr(0 to 39, 0 to 1)

    Arr() = FillArr(CurrDoc, Arr())

End Sub

Function FillArr(CurrentDocument As Word.Document, CurrentArray() As Variant) As Variant

    j = 1

    For Each chk In CurrentDocument.ContentControls

        If chk.Type = 8 Then

            CurrentArray(j, 1) = chk.Title
            CurrentArray(j, 2) = chk.Checked

            j = j + 1

        End If

    Next chk

FillArr() = CurrentArray()

End Function

【问题讨论】:

  • 你为什么用ReDim AnsArr(1 to 40, 1 to 2),却用Arr
  • ^ 并返回 CurrentArr(),它不会在其他任何地方使用。
  • Option Explicit FTW 另外,CurrDoc 没有,因为你没有设置它。
  • ^ 除了它不会标记ReDim AnsArr 中的AnsArr... 但无论如何,是的,您非常需要Option Explicit
  • 旁注,上面的每一条评论(以及更多评论)都将被报告为Rubberduck 的代码检查结果。 IMO 一个更好的方法是使用 Sub 程序来清楚地记录程序的副作用性质,然后让它接收一个 ByRef 数组(数组 have 被传递通过引用 anyway)复数名称参数:Private Sub GetContentControls(ByVal currentDocument As Word.Document, ByRef outControls() As Variant)(命名是关键!)。无论如何,请注意以下@Tomalak 的建议。干杯!

标签: arrays vba function


【解决方案1】:

我个人会以不同的方式处理这个问题。

返回所有“复选框”类型内容控件的标题和“选中”状态的函数的有用性低于仅返回特定类型的所有内容控件的函数的有用性。原因如下:

调用该函数的代码已经知道它想要使用TitleChecked,因此当它获取ContentControl 实例数组而不是字符串和布尔值的多维数组时不会丢失任何内容。但是当调用代码想要操作复选框时,“字符串和布尔值”方法就达不到要求了。

在这个假设下,我们可以去掉数组的一维,得到一个可以在不同场景中复用的函数。

我们也不需要任何数组传递。只需构建数组并返回它:

Function FindControls(Doc As Word.Document, ControlType As WdContentControlType) As Variant
    Dim cct As Variant, i As Integer

    ' figure out how many matching controls there are and allocate an array
    For Each cct In Doc.ContentControls
        If cct.Type = ControlType Then i = i + 1
    Next cct
    ReDim cctArray(i - 1)

    ' save references to matching controls in array
    i = 0
    For Each cct In Doc.ContentControls
        If cct.Type = ControlType Then
            Set cctArray(i) = cct
            i = i + 1
        End If
    Next cct

    FindControls = cctArray
End Function

现在我们可以很自然地在调用代码中使用它了:

Dim c As Variant

For Each c In FindControls(ActiveDocument, wdContentControlCheckbox)
    Debug.Print c.Title, c.Checked
Next

【讨论】:

  • 这...除了,为什么不返回 Collection 而只返回 .Add 对象,因为我们只迭代 Doc.ContentControls 一次?感谢避免循环内ReDim Preserve ...n+1 陷阱!
  • @Mathieu 我不知道...我本可以使用集合,但我得出的结论是它与使用数组相比没有足够的区别。在这种情况下,从调用代码的角度来看,它们的处理方式大致相同,并且调用代码中也不需要允许动态添加和删除项目的功能。所以我选择了数组。
  • 谢谢。与下面的 Warcupine 相比,此解决方案的相对优点是什么? Warcupine 的方法对我来说更直观。
  • @Michael 相对优点在第 3 段。另一个答案对您来说可能更直观,因为它看起来更像您的第一眼代码。在你判断之前,试着真正弄清楚我的代码做了什么。 (例如 - 40 是什么?为什么你的代码需要它而我的不需要?拥有不需要像这样的硬编码数字的代码不是更好吗?)跨度>
  • @Michael 如果你只对复选框状态感兴趣,那么只使用复选框状态。我认为返回布尔值的函数没有任何区别。你实际上什么也没有失去(写result(2) 来获得“已检查”状态与写result.Checked 一样复杂,但后者读起来很多更容易)并且你获得了大量的选择应该在那里曾经有一段时间你做的不仅仅是读出“检查”状态。
【解决方案2】:

我不想制作一个与您的完全匹配的 word 文档,但您可以通过函数传递数组。我要用随机字符填充我的。

Sub test()
    Dim arr() As Variant
    ReDim arr(1 To 40, 1 To 2)

    arr() = fillarr(arr())

    Dim i As Long

    For i = 1 To 40
        Debug.Print i, arr(i, 1)
        Debug.Print i & "* 5", arr(i, 2)
    Next i
End Sub

Function fillarr(currentarr() As Variant) As Variant
    Dim j As Long

    For j = 1 To 40
        currentarr(j, 1) = Chr(j + 64)
        currentarr(j, 2) = Chr(j * 5)
    Next j

    fillarr = currentarr
End Function

实际上有一个隐含的by ref,因为在 VBA 中数组总是通过引用传递,所以你实际上并不需要一个函数来执行此操作,尽管你可能应该这样做,因为它更清楚,但你可以在这里看到:

Sub test()
    Dim arr() As Variant
    ReDim arr(1 To 40, 1 To 2)

    fillarr arr() 'no value set

    Dim i As Long

    For i = 1 To 40
        Debug.Print i, arr(i, 1)
        Debug.Print i & "* 5", arr(i, 2)
    Next i
End Sub

Sub fillarr(currentarr() As Variant)
    Dim j As Long

    For j = 1 To 40
        currentarr(j, 1) = Chr(j + 64)
        currentarr(j, 2) = Chr(j * 5)
    Next j

    'Note the lack of return
End Sub

【讨论】:

  • 看起来我的错误出现在我的返回行中:FillArr = CurrentArr() 而不是 FillArr() = CurrentArr()。这是为什么呢?
  • 因为它认为这是一个函数调用并需要参数,所以CurrentArr() 也不应该有它(我认为,虽然我不肯定,但在声明之后它已知是一个数组,除非你需要重新调整或索引它是不需要的),那是我的错。
  • 我知道 CurrentArr() 需要它以确保在声明数组时它是 Variant 类型元素的 Variant 类型数组。函数调用位非常有意义,谢谢。
猜你喜欢
  • 1970-01-01
  • 2018-09-23
  • 2015-06-04
  • 1970-01-01
  • 2014-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多