获取可变参数列表的Swift等效# define

3

So I have a function in C that works as

#define PRINTF(format) { va_list list; va_start(list, format); vprintf(format, list);}

void foo(const char* format, ...) {
   PRINTF(format)
}

我在想如果我要制作一个Swift等效的上述代码,我应该如何表示… as? 我知道如何使用可变参数类型CVarArgType,或者使用参数数组。但是,由于此C代码片段使用宏,我发现很难将此代码移植到Swift中而不更改我制作的函数的参数。我能否得到任何洞察力或帮助,以了解如何做这样的事情?
我需要帮助编写Swift中#define宏等效函数,并且遇到了麻烦,无法创建va_list列表,va_start调用的等效物。

苹果公司认为(我也倾向于同意)#define宏会使调试变得更加困难,因此在Swift中不允许使用。话虽如此,在Swift中可能仍然有一种方法来接受可变数量的参数。 - nhgrif
不清楚你到底在问什么。你是想知道如何调用一个使用 va_list 的 C 函数吗?(如果是的话:withVaList([1, 1.2]) { vprintf("an int: %d\na float: %f", $0) } 将可行)。还是你在问如何在 Swift 中声明可变参数函数?或者一般而言,你想知道如何在 Swift 中定义宏 #define 吗? - Airspeed Velocity
基本上,我需要帮助将上述代码转换为Swift等效代码。由于Swift不允许宏,我认为我需要编写一个函数来代替它。我不确定如何在Swift中复制上面宏的行为,特别是va_list列表,va_start调用。 - Kunal
好的,看起来你遇到了一个XY问题,也就是说你想知道如何调用一个C变量参数函数,但是你提问关于#define宏。不过@nhgrif的回答已经解决了你的问题 :) - Airspeed Velocity
1个回答

2

嗯,我的原始答案绝对使事情过于复杂...

我们需要为格式取一个String,并使用一个CVarArgType...的参数列表(在函数内被视为[CVarArgType])。我试图使用Objective-C的NSString来使它变得复杂。如果我们坚持使用Swift的String,它实际上有一个接受我们传递的参数的初始化器。

在Swift中编写此函数的最简单方法如下:

func foo(format: String, args: CVarArgType...) {
    println(String(format: format, arguments: args))
}

据我所知,Swift不允许使用#define宏。但是,我们可以将该C宏转换为常规的Swift函数。
func foo(format: String, args: CVarArgType...) {
    println(NSString(format: format, arguments: getVaList(args)))
}

CVarArgType 是一个 Swift 协议,它接受我们通常传递给字符串格式字符串的类型。

... 使函数接受任意数量的参数作为最后一个参数。在函数内部,这将具有类型 [CVarArgType](一个数组)。

与此同时,NSString 的初始化器(以及类似的 NSLog 和其他类似位置)正在寻找一个 CVaListPointer 作为最后一个参数,因此我们可以使用 Swift 的内置函数 getVaList,将 [CVarArgType] 转换为 CVaListPointer

可以这样调用此函数:

foo("%@, %@... %i", "hello", "world", 123)

这将打印:

hello, world... 123

正如@AirspeedVelocity所指出的,通常建议使用withVaList而不是getVaList。我们可以这样做:

func foo(format: String, args: CVarArgType...) {
    func buildLogString(argList: CVaListPointer) -> String {
        return NSString(format: format, arguments: argList) as String
    }
    println(withVaList(args, buildLogString))
}

对于超出此特定示例的应用程序,重要的是要注意我们可以使用...来接受任何类型的参数列表,在函数内部,我们得到该类型的数组。

例如:

func bar(myVariadicListOfStuff: MyStuffClass...) {
    // myVariadicListOfStuff is a [MyStuffClass]
    for thing in myVariadicListOfStuff {
        // this is a MyStuffClass
    }
}

请注意,正如上面关于getVaList的文档注释所说,“警告:最好使用withVaList代替此函数”。 - Airspeed Velocity
@AirspeedVelocity 我更新了答案...感觉自己过于复杂化了,呵呵。看看答案的新顶部部分... - nhgrif

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接