我发现Swift 3.1中String的#function文字返回的内容很奇怪。这里:
class FunctionLiteralTest {
    func weirdo() -> String {
        return #function
    }
    func weirdo(parameter: Int) -> String {
        return #function
    }
    func weirdo(_ parameter: Int) -> String {
        return #function
    }
    func weirdo(_ parameter: Int, _ anotherParameter: Int) -> String {
        return #function
    }
}
let functionLiteralTest = FunctionLiteralTest()
functionLiteralTest.weirdo()             // returns "weirdo()"
functionLiteralTest.weirdo(parameter: 1) // returns "weirdo(parameter:)"
functionLiteralTest.weirdo(1)            // returns "weirdo"
functionLiteralTest.weirdo(1, 2)         // returns "weirdo"
当未标记所有参数时,将完全跳过括号。我很明白,如果#function返回的函数名也没有括号,也就没有任何参数。
那是合理的行为还是错误?
在 Swift 5(尚未正式发布,但您可以获取主快照)中,由于#19062修复了这种不一致。您的代码现在输出以下内容:
functionLiteralTest.weirdo()             // returns "weirdo()"
functionLiteralTest.weirdo(parameter: 1) // returns "weirdo(parameter:)"
functionLiteralTest.weirdo(1)            // returns "weirdo(_:)"
functionLiteralTest.weirdo(1, 2)         // returns "weirdo(_:_:)"
我同意这是完全令人困惑的行为,但它似乎是故意的。
函数字面量在 SILGen 的过程中被“填充”;这是通过SILGenApply.cpp 中的SILGenFunction::emitLiteral函数完成的。
然后调用到getMagicFunctionString函数文字:
Run Code Online (Sandbox Code Playgroud)static StringRef getMagicFunctionString(SILGenFunction &SGF) { assert(SGF.MagicFunctionName && "asking for #function but we don't have a function name?!"); if (SGF.MagicFunctionString.empty()) { llvm::raw_string_ostream os(SGF.MagicFunctionString); SGF.MagicFunctionName.printPretty(os); } return SGF.MagicFunctionString; }
其中,如果尚未产生,创建一个新的流输出MagicFunctionString,并呼吁DeclName::printPretty对MagicFunctionName与此流:
Run Code Online (Sandbox Code Playgroud)llvm::raw_ostream &DeclName::printPretty(llvm::raw_ostream &os) const { return print(os, /*skipEmptyArgumentNames=*/true); }
(在函数发出时MagicFunctionName赋值;并被赋予 的值,这只是声明的 ) getFullName()Name
然后调用 on DeclName::print,它作为它的第二个参数接受一个布尔参数来确定是否跳过列出参数名称,如果它们都是空的:
Run Code Online (Sandbox Code Playgroud)llvm::raw_ostream &DeclName::print(llvm::raw_ostream &os, bool skipEmptyArgumentNames) const { // Print the base name. os << getBaseName(); // If this is a simple name, we're done. if (isSimpleName()) return os; if (skipEmptyArgumentNames) { // If there is more than one argument yet none of them have names, // we're done. if (getArgumentNames().size() > 0) { bool anyNonEmptyNames = false; for (auto c : getArgumentNames()) { if (!c.empty()) { anyNonEmptyNames = true; break; } } if (!anyNonEmptyNames) return os; } } // Print the argument names. os << "("; for (auto c : getArgumentNames()) { os << c << ':'; } os << ")"; return os; }
你可以看到,因为如果状态if (getArgumentNames().size() > 0),不带参数的功能会跳过所有空参数名称检查,导致他们被发射与括号,例如weirdo()。但是带有一个或多个参数的函数,所有参数名称都是空的,在发出时不带括号,例如weirdo.
因此,考虑到参数的DeclName::printPretty特定传递true,skipEmptyArgumentNamesSwift 团队似乎确实特别希望为#function.
此外,如果我们查看blame,我们可以看到DeclName::printPretty在此提交中添加了它,并带有提交消息:
通过删除带括号的位,漂亮地打印没有关键字参数的 DeclNames。
而不是打印“
f(_:_:)”,只需打印“f”。
话虽如此,我仍然会针对它提交错误报告,因为它对于函数文字来说似乎并不那么直观。
| 归档时间: | 
 | 
| 查看次数: | 855 次 | 
| 最近记录: |