【问题标题】:excel vba: Special Types - Functions as Arguments of Functionsexcel vba:特殊类型 - 作为函数参数的函数
【发布时间】:2025-12-11 03:45:01
【问题描述】:

VBA 中的函数没有特殊类型。我很难理解如何将函数作为参数添加到 Excel VBA 中的函数。

我想要完成的是这样的:

function f(g as function, x as string) as string
        f = g(x)
end function

目前,我有一组小函数,它们都在重复自己,但只调用一个特定函数。

【问题讨论】:

    标签: function excel functional-programming arguments vba


    【解决方案1】:

    从您的代码中,函数 g 接受一个字符串参数并返回一个字符串。我建议你创建一个名为 IStringFunction 的类模块来定义所有函数都支持的接口,因此:

    类模块:IStringFunction

    Public Function Evaluate(ByVal s As String) As String
    End Function
    

    然后,创建几个实现该接口的示例函数:

    类模块:HelloStringFunction

    Implements IStringFunction
    
    Public Function IStringFunction_Evaluate(ByVal s As String) As String
        IStringFunction_Evaluate = "hello " & s
    End Function
    

    类模块:GoodbyeStringFunction

    Implements IStringFunction
    
    Public Function IStringFunction_Evaluate(ByVal s As String) As String
        IStringFunction_Evaluate = "goodbye " & s
    End Function
    

    ...最后,一些测试代码来执行这些功能:

    (标准)模块:测试

    Sub Test()
    
        Dim oHello As New HelloStringFunction
        Dim oGoodbye As New GoodbyeStringFunction
    
        MsgBox Evaluate(oHello, "gary")
        MsgBox Evaluate(oGoodbye, "gary")
    
    End Sub
    
    Private Function Evaluate(ByVal f As IStringFunction, ByVal arg As String) As String
        Evaluate = f.Evaluate(arg)
    End Function
    

    请注意,实现接口的类必须具有如上例中名为 <Interface>_<Method> 的方法,而不仅仅是您所期望的 <Method>

    在此处下载simple demointermediate demo

    【讨论】:

    • 这并没有真正帮助他,因为他仍然必须为每个类编写一个单独的评估函数。
    • @Treb:也许我不明白这个问题,但我不明白你的意思。每个类代表一个不同的功能,所以它当然必须有一个单独的评估功能!如果问题可以重新陈述,也许会更清楚。
    • 嗨,我认为这是正确的答案。这是在 oo 语言中执行此操作的方法,我只是不知道 VBA 中存在接口——我的错。我记得在 a little java 中第一次看到这种技术。但我必须测试提出的解决方案。目前我收到一条关于未实现接口的错误消息。 Public Function apply(ByVal tmp As Variant) As Boolean End Function --- 实现 IBoleanFunction Public Function apply(ByVal tmp As Variant) As Boolean apply = Application.IsText(tmp) End Function
    • 罗马,你需要在函数名前加上它实现的接口的名字,所以如果接口叫IFoo,方法叫Bar,那么在你的实现类中必须调用方法IFoo_Bar。
    【解决方案2】:

    由于 VBA 植根于交互式语言,它始终具有执行文本的能力:

    function f(g as string, x as string) as string
            f = application.run(g,x)
    end function
    
    MyStringA = f("functionA",string1)
    MyStringB = f("functionB",string1)
    

    编辑添加: 我认为在当前版本的 Excel 中,应用程序 (Excel) 只能“运行”您可以在电子表格单元格中显示的内容。所以这意味着函数,而不是子例程。要执行子例程,请将其包装在函数包装器中:

    function functionA(x as string)
        Call MySubA(x)
    end function
    

    【讨论】:

    • 这很好,但我认为它实际上与传递函数的作用域不同......
    • 那是涂料!不管有没有理想的范围,我都会接受。
    • 在 Excel VBA 2010 中,此语法给出编译错误“预期:语句结束”。参数需要用括号括起来:f = Application.Run(g,x)
    • @JS,我猜这个解决方案在g 是一个函数时有效,但在它是一个子例程时无效。我正在尝试使用子例程,但出现编译错误。你知道如何实现它来调用子程序吗?
    【解决方案3】:

    可以将函数作为参数传递,并准确获得您所追求的行为,但这有点hacky。这是通过利用类的默认属性来实现的,

    创建一个包含您的函数的类myFunction

    Public Function sayHi(ByVal s As String) As String
        sayHi = "Hi " & s
    End Function
    

    导出它,然后在文本编辑器中打开 .cls 文件

    您应该在文件中的某处看到定义函数的行

    Public Function sayHi(ByVal s As String) As String
    

    在它下面,添加行Attribute Value.VB_UserMemId = 0,现在它看起来像这样:

    Public Function sayHi(ByVal s As String) As String
    Attribute Value.VB_UserMemId = 0
        sayHi = "Hi " & s
    End Function
    

    您在这里所做的是将sayHi 标记为班级的default property。现在可以通过类对象单独调用函数class(args),而不是class.function(args)

    保存修改后的文件并将其导入您的 VBA 项目

    测试模块

    Sub test()
        Dim parameterFunction As Object         'this is what we'll be passing to our routine
        Set parameterFunction = New myFunction  'create instance of the function object
        MsgBox f(parameterFunction, "Greedo")
    End Sub
    
    Function f(ByVal g As Object, ByVal x As String) As String
            f = g(x)
    End Function
    

    *NB,这样你可以传递任何函数;但您可以改为指定 ByVal g As IStringFunction 以仅获取具有正确接口的子集,如 Gary McGill's answer

    【讨论】:

    • 注意,您可以通过在函数签名上方添加 Rubberduck 的 '@DefaultMember 属性来避免所有导入/导出。对于纯/静态风格的函数,您可以使用'@PredeclaredId 属性并传递类的默认实例以避免每次都对其进行更新。另请参阅 this 关于 vba 中的一流函数的帖子
    • 一个更好的实现:codereview.stackexchange.com/q/138557/146810,另一种使用真实函数指针的方法:codeproject.com/Articles/204509/Functors-in-VBA