例如:
struct L {
#if DEBUG
static let og:((String) -> Void)? = { print($0) }
#else
static let og:((String) -> Void)? = nil
#endif
}
L.og?("Howdy!")
print("Done.")
在此代码的发布版本中,Swift 编译器如何处理 L.og?("Howdy!")
行?它是否完全优化了线路?或者表达式 L.og
在运行时评估为 nil
?我如何证明任一答案?
最佳答案
我想我终于回答了我自己的问题。这次修改完全取代了我之前的回答,因为我认为这是错误的。
简答
编译器优化不会删除 Release
构建中的 L.og?("Howdy!")
行。 og?
的解包仍然在运行时发生。
证明
定义“发布”
在一个典型的Xcode项目中,Release
的优化是什么?在目标build设置中,它是 SWIFT_OPTIMIZATION_LEVEL = -O
。
方法
我在 2 个不同的程序上运行了 swiftc -emit-assembly -O
。
程序A:
struct L {
#if DEBUG
static let og:((String) -> Void)? = { print($0) }
#else
static let og:((String) -> Void)? = nil
#endif
}
L.og?("Howdy!")
程序 B:
struct L {
#if DEBUG
static let og:((String) -> Void)? = { print($0) }
#else
static let og:((String) -> Void)? = nil
#endif
}
在程序集输出中,A
中的main
_main:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
pushq %r13
pushq %rax
.cfi_offset %r13, -24
cmpq $-1, _globalinit_029_12232F587A4C5CD8B1EEDF696793B2FC_token0(%rip)
jne LBB0_4
LBB0_1:
movq _$s4main1LV2ogySScSgvpZ(%rip), %rax
testq %rax, %rax
je LBB0_3
movq _$s4main1LV2ogySScSgvpZ+8(%rip), %r13
movabsq $36805260308296, %rdi
movabsq $-1873497444986126336, %rsi
callq *%rax
LBB0_3:
xorl %eax, %eax
addq $8, %rsp
popq %r13
popq %rbp
retq
LBB0_4:
leaq _globalinit_029_12232F587A4C5CD8B1EEDF696793B2FC_token0(%rip), %rdi
leaq _globalinit_029_12232F587A4C5CD8B1EEDF696793B2FC_func0(%rip), %rsi
callq _swift_once
jmp LBB0_1
.cfi_endproc
.p2align 4, 0x90
和B:
_main:
pushq %rbp
movq %rsp, %rbp
xorl %eax, %eax
popq %rbp
retq
.p2align 4, 0x90
如果编译器优化掉整行 L.og?("Howdy!")
,那么我希望 main
来自 B将与 A 相同。它不是。因此,编译器将其保留。
非可选结果
对于非可选的空闭包,发现了类似的结果。对 L.og("Howdy!")
的调用保留在优化的程序集中,即使调用的是一个空函数。
即:
struct L {
#if DEBUG
static let og:((String) -> Void) = { print($0) }
#else
static let og:((String) -> Void) = { _ in }
#endif
}
L.og("Howdy!")
这是优化的 main
程序集:
_main:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
pushq %r13
pushq %rax
.cfi_offset %r13, -24
cmpq $-1, _globalinit_029_12232F587A4C5CD8B1EEDF696793B2FC_token0(%rip)
jne LBB0_1
LBB0_2:
movq _$s4main1LV2ogyySScvpZ+8(%rip), %r13
movabsq $36805260308296, %rdi
movabsq $-1873497444986126336, %rsi
callq *_$s4main1LV2ogyySScvpZ(%rip)
xorl %eax, %eax
addq $8, %rsp
popq %r13
popq %rbp
retq
LBB0_1:
leaq _globalinit_029_12232F587A4C5CD8B1EEDF696793B2FC_token0(%rip), %rdi
leaq _globalinit_029_12232F587A4C5CD8B1EEDF696793B2FC_func0(%rip), %rsi
callq _swift_once
jmp LBB0_2
.cfi_endproc
.p2align 4, 0x90
关于swift - 仅在条件编译 block 中设置可选,编译器是否从发布版本中完全删除语句?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58454708/