Swift 3.1中#function文字的怪异值

Rob*_*bok 5 function swift

我发现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"
Run Code Online (Sandbox Code Playgroud)

当未标记所有参数时,将完全跳过括号。我很明白,如果#function返回的函数名也没有括号,也就没有任何参数。

那是合理的行为还是错误?

Ham*_*ish 6

斯威夫特 5 更新

在 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(_:_:)"
Run Code Online (Sandbox Code Playgroud)

斯威夫特 5 之前

我同意这是完全令人困惑的行为,但它似乎是故意的。

函数字面量在 SILGen 的过程中被“填充”;这是通过SILGenApply.cpp 中SILGenFunction::emitLiteral函数完成的

然后调用到getMagicFunctionString函数文字:

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;
}
Run Code Online (Sandbox Code Playgroud)

其中,如果尚未产生,创建一个新的流输出MagicFunctionString,并呼吁DeclName::printPrettyMagicFunctionName与此流:

llvm::raw_ostream &DeclName::printPretty(llvm::raw_ostream &os) const {
  return print(os, /*skipEmptyArgumentNames=*/true);
}
Run Code Online (Sandbox Code Playgroud)

(在函数发出时MagicFunctionName赋值;并被赋予 的值,这只是声明的 ) getFullName()Name

然后调用 on DeclName::print,它作为它的第二个参数接受一个布尔参数来确定是否跳过列出参数名称,如果它们都是空的:

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;

}
Run Code Online (Sandbox Code Playgroud)

你可以看到,因为如果状态if (getArgumentNames().size() > 0),不带参数的功能会跳过所有空参数名称检查,导致他们被发射括号,例如weirdo()。但是带有一个或多个参数的函数,所有参数名称都是空的,在发出时不带括号,例如weirdo.

因此,考虑到参数的DeclName::printPretty特定传递trueskipEmptyArgumentNamesSwift 团队似乎确实特别希望为#function.

此外,如果我们查看blame,我们可以看到DeclName::printPretty此提交中添加了,并带有提交消息:

通过删除带括号的位,漂亮地打印没有关键字参数的 DeclNames。

而不是打印“ f(_:_:)”,只需打印“ f”。

话虽如此,我仍然会针对它提交错误报告,因为它对于函数文字来说似乎并不那么直观。