繁体   English   中英

从文字创建数组时的 Swift 宏

[英]Swift macros when creating Array from literals

对于下面的代码:

let services: [MyServices] = [
    MyService(),
    #if DEBUG
    DebugService(),
    #endif
]

我收到编译器错误:

表达式无法解析:错误:MyPlayground.playground:375:5:错误:容器文字中的预期表达式#if DEBUG ^

错误:MyPlayground.playground:376:19: 错误:一行中的连续语句必须用“;”分隔调试服务(), ^;

错误:MyPlayground.playground:376:19: 错误:预期表达式 DebugService(), ^

错误:MyPlayground.playground:378:1:错误:预期的表达]

但相同的代码适用于 Objective-C

NSArray *array = @[
        @"11",
    #if DEBUG
        @"debug",
    #endif
        @"22"
    ];

这是编译器错误还是预期行为? 谢谢。

#if / #endif结构不像 C 那样是预处理器宏。它们是编译器指令。 它们是语言的一部分。

在 C 中,它会在您的源文件上运行预处理器,从而生成经过修改的源文件。 修改后的源文件被编译。

在 Swift 中不是这样。在 Swift 中,编译器解析源文件并尝试编译它。


编辑:

要理解为什么您尝试的方法不起作用,请将#if / #endif想象成一个常规的 if 语句。 以下会编译吗?

let debug = true
let services: [MyServices] = [
    MyService(),
    if debug {
        DebugService(),
    }
]

(答案:不。那是不合法的。您不能在数组初始值设定项的参数中间插入 if 语句。 #if / #elseif语句也是如此。)


您不能使用#if / #endif块将语句的片段组合在一起。

在这两种情况下,您都必须创建完整的语句:

#if debug
    let services: [MyServices] = [
        MyService(),
        DebugService(),
    ]
#else
    let services: [MyServices] = [
        MyService()
    ]
#endif

(或者您可以将services设为 var,并在#if / #endif中将其设为 append DebugServices() 。)


编辑#2:

更好的是,使用“后缀” .appending()就像@MartinR 的出色答案一样。

通常, #if... #else... #endif编译器指令中每个子句的主体必须包围完整的语句。

但是随着 Swift 5.5 中后缀成员表达式的 SE-308 #if的实现,这个指令已经扩展到能够包围后缀成员表达式。

所以有了自定义扩展

extension Array {
    func appending(_ e: Element) -> Self {
        return self + [e]
    }
}

可以像这样有条件地初始化一个数组:

let services = [
    MyService() ]
#if DEBUG
    .appending(DebugService())
#endif

Swift 5.5

let services: [MyServices] = [
    #if DEBUG
    DebugService()
    #else
    MyService()
    #endif
]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM