Recursion 递归调用函数,无需附加参数

Recursion 递归调用函数,无需附加参数,recursion,vbscript,Recursion,Vbscript,我编写了vbscript函数,用于搜索Unix上的可用端口列表。因此,我的代码如下所示: Function FindFreePorts(ByVal intPortToStart, ByVal intCountOfPortToSearch, ByVal arrFreePorts) Dim i, arrCommand, arrTmp, blnFindAllPort, j, strCommand Dim blnFree, intCountOfFreePorts strCommand

我编写了vbscript函数,用于搜索Unix上的可用端口列表。因此,我的代码如下所示:

Function FindFreePorts(ByVal intPortToStart, ByVal intCountOfPortToSearch, ByVal arrFreePorts)
   Dim i, arrCommand, arrTmp, blnFindAllPort, j, strCommand
   Dim blnFree, intCountOfFreePorts

   strCommand = "lsof -i | awk '{print $8}' | sed -n '/"    
   For i = intPortToStart To intPortToStart+intCountOfPortToSearch - 1
       If i = intPortToStart+intCountOfPortToSearch - 1 Then
           strCommand = strCommand & ".*"& i & "$/s/.*://p'"
       Else
           strCommand = strCommand & ".*:" & i &"\|"
       End If     
   Next

   Push arrCommand, strCommand  
   arrTmp = Array() 
   arrTmp = ExecuteCommandOnUnix(arrCommand, Null, _
                                                                        Environment.Value("UNIXHOST_NAME"), _
                                                                        Environment.Value("UNIXHOST_USER"), _
                                                                        Environment.Value("UNIXHOST_PWD"))  
   ' Count of busy port is UBound(arrTmp) - the other ports are free
   ' Find free ports
   intCountOfFreePorts = intCountOfPortToSearch 
    For i = intPortToStart To intPortToStart+intCountOfPortToSearch - 1
        blnFree = True
        For j = 0 To UBound(arrTmp)
            If arrTmp(j) = CStr(i) Then
                blnFree = False
                j = UBound(arrTmp)
            End If
        Next
        If blnFree Then
            Push arrFreePorts, i
            intCountOfFreePorts = intCountOfFreePorts - 1
        End If
    Next
    '
   If  intCountOfFreePorts = 0 Then
       blnFindAllPort = True
   Else
        blnFindAllPort = False
   End If

   If Not blnFindAllPort Then
       ' We found UBound(arrFreePorts), we need to find intCountOfPortToSearch - UBound(arrFreePorts) 
       Do While intCountOfPortToSearch - UBound(arrFreePorts) - 1 <> 0
                arrFreePorts = FindFreePorts(intPortToStart + intCountOfPortToSearch + 1, intCountOfPortToSearch - UBound(arrFreePorts) - 1, arrFreePorts)
                If intCountOfPortToSearch - UBound(arrFreePorts) - 1 = 0 Then
                    Exit Do
                End If
       Loop
   End If

    FindFreePorts = arrFreePorts
End Function
但是我不知道如何在没有这个参数的情况下重写这个函数。然后我可以用更简单的方式来称呼它:

arrPort = FindFreePorts(intStartFromPort, intCountToSearch)

谢谢。

为了保持事物(实验,说明“邦德的贡献”)简单,让我们考虑把字符串的字符放进数组中的任务。

返回数组(不通过参数或全局获取)的函数需要创建数组:

Function f1(s) ' default ByRef is ok, because Left and Mid return new (sub)strings
  If "" = s Then
     f1 = Array() ' return empty array for empty string
  Else
     Dim t : t = f1(Mid(s, 2)) ' recurse for tail - sorry no tail recursion
     f1 = cons(Left(s, 1), t) ' copy! result of cons to f1/function's return value
  End If
End Function
阵列的增长可以内联完成,但为了清晰起见,我使用了一个辅助函数:

调用函数很好:

  WScript.Echo 3, "[" & Join(f1("12456789"), ",") & "]"
避免传递“The”数组的代价:

  • 大量副本(VBScript中的阵列分配副本)
  • 否(但是,我怀疑VBScript是否利用了它)
  • 比下面的子方法((c)Bond)慢大约因子10
  • 在这种情况下,递归调用可以/应该在“相同”数组上工作,Sub可以更有效地执行任务(并且不那么复杂):

    但这可以通过包装来避免:

    Function f2(s)
      ReDim aTmp(-1)
      s1 s, aTmp
      f2 = aTmp
    End Function
    

    如果我正确地读取了代码,那么看起来每次函数调用都会传递数组的副本。由于您使用的是递归,因此可能会有很多副本!为什么不在调用作用域(最初调用
    findfreeport
    的作用域)中声明一个数组,并通过引用将该数组传递给
    findfreeport
    。现在,您只需传递对数组的引用,而不是每次传递数组的副本。而且您不必返回它,这样您的
    函数
    就可以成为
    子函数
    。不过,您仍然需要您的
    推送
    例程来动态增长阵列。谢谢,照您说的做了,一切正常,但速度更快:)谢谢,请澄清:)
      WScript.Echo 3, "[" & Join(f1("12456789"), ",") & "]"
    
    Sub s1(s, a) ' default ByRef is ok; a should be modified, s isn't touched
      If "" <> s Then
         ReDim Preserve a(UBound(a) + 1) ' grow! a
         a(UBound(a)) = Left(s, 1)
         s1 Mid(s, 2), a ' tail recursion for tail
      End If
    End Sub
    
      ReDim a(-1) : s1 "123456789", a : WScript.Echo 3, "[" & Join(a, ",") & "]"
    
    Function f2(s)
      ReDim aTmp(-1)
      s1 s, aTmp
      f2 = aTmp
    End Function