Swift等效于#define来检索变量参数列表

时间:2015-05-20 22:14:28

标签: swift macros

所以我在C中有一个函数

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

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

我想知道我是否要将Swift等同于上面的代码,我将如何代表......作为?我知道如何使用变量参数的唯一方法是使用CVarArgType,或使用参数数组。

但是,由于这个C片段使用了一个宏,我发现很难将这个代码移植到Swift而不改变我所做的函数的参数而不是宏。关于如何做这样的事情,我能获得任何见解或帮助吗?

我需要帮助在Swift中编写#define宏等效函数,并且在提供等效于va_list列表,va_start调用时遇到问题。

1 个答案:

答案 0 :(得分:2)

好吧,我原来的答案绝对让事情过于复杂......

我们需要String为格式,CVarArgType...为参数列表(在{1}}内被视为[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协议,它接受我们通常传入String的格式字符串。

...使函数接受最后一个参数的任意数量的参数。在函数中,它将具有类型[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
    }
}