VBScript高阶函数

时间:2015-03-24 17:33:11

标签: vbscript functional-programming

有没有办法编写匿名函数,在vbscript中将它们传递给调用它们的其他函数?

3 个答案:

答案 0 :(得分:2)

  1. VBScript中没有匿名函数/ subs / methods。
  2. 您可以使用GetRef()(请参阅sample1sample2)来获取类似函数指针的内容,该函数指针可以传递给要调用的函数/ subs(回调)。但是VBScript中没有闭包,因此其他语言中的技巧可能在VBScript中失败。
  3. 对于可以通过函数式语言中的高阶函数解决的特定问题,可能存在(几乎)等同于涉及类/对象的VBScript解决方案;但是为了讨论这种方法,你需要详细描述你的/这样的问题。

答案 1 :(得分:0)

VBScript能够执行仲裁代码。

执行和Eval只是对包含代码的字符串执行他们所说的内容。

ExecuteGlobal将代码添加到程序中,如新函数,新变量。

Script Control将vbscript / jscript脚本语言添加到任何程序,包括vbscripts。它可以访问主机的数据。

如果使用ExecuteGlobal / Execute / Eval,最好先运行一个scriptcontrol来测试语法错误(因为你不能捕获语法错误,但你可以捕获脚本控件在语法错误时发出的运行时错误)。

因此,您可以在运行时构建程序。

Set Arg = WScript.Arguments
set WshShell = createObject("Wscript.Shell")
Set Inp = WScript.Stdin
Set Outp = Wscript.Stdout

Sub VBSCmd
    RawScript = LCase(Arg(1))
    'Remove ^ from quoting command line and replace : with vbcrlf so get line number if error
    Script = Replace(RawScript, "^", "")
    Script = Replace(Script, "'", chr(34))
    Script = Replace(Script, ":", vbcrlf)
    'Building the script with predefined statements and the user's code
    Script = "Dim gU" & vbcrlf & "Dim gdU" & vbcrlf & "Set gdU = CreateObject(" & chr(34) & "Scripting.Dictionary" & chr(34) & ")" & vbcrlf & "Function UF(L, LC)" & vbcrlf & "Set greU = New RegExp" & vbcrlf & "On Error Resume Next" & vbcrlf & Script & vbcrlf & "End Function" & vbcrlf

    'Testing the script for syntax errors
    On Error Resume Next
    set ScriptControl1 = wscript.createObject("MSScriptControl.ScriptControl",SC)
        With ScriptControl1
            .Language = "VBScript"
            .UseSafeSubset = False
            .AllowUI = True
        .AddCode Script
    End With
    With ScriptControl1.Error
        If .number <> 0 then
            Outp.WriteBlankLines(1)
            Outp.WriteLine "User function syntax error"
            Outp.WriteLine "=========================="
            Outp.WriteBlankLines(1)
            Outp.Write NumberScript(Script)
            Outp.WriteBlankLines(2)
            Outp.WriteLine "Error " & .number & " " & .description
            Outp.WriteLine "Line " & .line & " " & "Col " & .column
            Exit Sub
        End If
    End With

    ExecuteGlobal(Script)

    'Remove the first line as the parameters are the first line
    'Line=Inp.readline  
    Do Until Inp.AtEndOfStream
        Line=Inp.readline
        LineCount = Inp.Line 

        temp = UF(Line, LineCount)
        If err.number <> 0 then 
            outp.writeline ""
            outp.writeline ""
            outp.writeline "User function runtime error"
            outp.writeline "==========================="
            Outp.WriteBlankLines(1)
            Outp.Write NumberScript(Script)
            Outp.WriteBlankLines(2)
            Outp.WriteLine "Error " & err.number & " " & err.description
            Outp.WriteLine "Source " & err.source

            Outp.WriteLine "Line number and column not available for runtime errors"
            wscript.quit
        End If
        outp.writeline temp
    Loop
End Sub

了Vbs

filter vbs "text of a vbs script"
filter vb "text of a vbs script"

使用冒号分隔语句和行。使用单引号代替双引号,如果需要单引号,请使用chr(39)。使用^字符转义括号和&符号。如果你需要插入符号,请使用chr(136)。

该函数称为UF(用于UserFunction)。它有两个参数,L包含当前行,LC包含linecount。将脚本的结果设置为UF。见例。

有三个全局对象可用。未声明的全局变量gU,用于维护状态。如果需要多个变量,请将其用作数组。用于保存和访问前一行的Dictionary对象gdU。并且可以使用RegExp对象greU。

实施例

此vbs脚本插入行号并将行设置为过滤器打印的函数UF。

filter vbs "uf=LC ^& ' ' ^& L"<"%systemroot%\win.ini"

这就是它在内存中的样子

Dim gU
Set gdU = CreateObject("Scripting.Dictionary")
Set greU = New RegExp

Function UF(L, LC)

---from command line---
    uf=LC & " " & L
---end from command line---

End Function

如果存在语法错误,Filter将显示调试详细信息。

User function syntax error
==========================


1 Dim gU
2 Dim gdU
3 Set greU = CreateObject("Scripting.Dictionary")
4 Function UF(L, LC)
5 On Error Resume Next
6 uf=LC dim & " " & L
7 End Function

Error 1025 Expected end of statement
Line 6 Col 6


User function runtime error
===========================


1 Dim gU
2 Dim gdU
3 Set greU = CreateObject("Scripting.Dictionary")
4 Function UF(L, LC)
5 On Error Resume Next
6 uf=LC/0 & " " & L
7 End Function

Error 11 Division by zero
Source Microsoft VBScript runtime error
Line number and column not available for runtime errors

答案 2 :(得分:0)

关于函数对象的有趣之处在于它们根据定义是内存泄漏。这意味着一旦你创建了一个函数对象,你需要保持它完整创建的范围,这让我失望。

Class VBCompiler    
    Public leaks

    Public Sub Class_Initialize()
        leaks = Array()
    End Sub

    Public Function Compile(code)
        Dim compiler, result

        Set compiler = CreateObject("MSScriptControl.ScriptControl")
        Set portal = CreateObject("Scripting.Dictionary")
        Dim name

        compiler.Language = "VBScript"
        compiler.AddObject "portal", portal, True
        compiler.ExecuteStatement code
        name = compiler.Procedures(1).Name
        compiler.ExecuteStatement "portal.Add ""result"", GetRef(""" & name & """)"

        ' save the script control because if we go out of scope...
        ' our function object goes poof!
        ' leaks.Push compiler
        ReDim Preserve leaks(UBound(leaks) + 1)
        Set leaks(UBound(leaks)) = compiler

        Set Compile = portal("result")
    End Function
End Class

Dim z
Set z = New VBCompiler
Set z2 = z.Compile("Function Foo(s):MsgBox s:Foo = 2:End Function")
z2("Hi!")
z2 "Hello Again!"

根据需要提供两个消息框

Class VBCompiler    
    Public Function Compile(code)
        Dim compiler, result

        Set compiler = CreateObject("MSScriptControl.ScriptControl")
        Set portal = CreateObject("Scripting.Dictionary")
        Dim name

        compiler.Language = "VBScript"
        compiler.AddObject "portal", portal, True
        compiler.ExecuteStatement code
        name = compiler.Procedures(1).Name
        compiler.ExecuteStatement "portal.Add ""result"", GetRef(""Foo"") "             
        Set Compile = portal("result")
    End Function
End Class

Dim z
Set z = New VBCompiler
Set z2 = z.Compile("Function Foo():MsgBox ""Well Met!"":Foo = 2:End Function")
z2("Hi!")
z2 "Hello Again!"

上面给出了(29, 5) (null): Unspecified error。这个错误本质上是:your object has committed suicide

这种方法可以改进(特别是每个编译浪费一个ScriptControl而没有任何计划发布它们的问题)。