我正在学习Swift,但是为什么在调用函数时不需要第一个参数的名称却很奇怪。

func say(greeting: String, toName: String) {
    print("\greeting), \(toName)!")
}

say("Goodbye", toName: "Hollywood") // <-- why is there no "greeting" required?

最佳答案

正如其他人所说,这是源于Objective-C的样式问题。

要了解为什么有人想要这种样式,请考虑对您的示例进行修改:

func say(greeting: String) {
    print("\(greeting)")
}

您会这​​样称呼:
say("Hello!")

当您查看使用的名称时,可以说缺少一些信息。使用say()函数,您可能会合理地认为这是一个让您说什么的函数。但是,当您查看参数名称时,很显然,这是一个用来说问候语,而不是说任何东西的函数。

因此,Objective-C希望您这样编写:
func sayGreeting(greeting: String) {
    print("\(greeting)")
}

您会这​​样称呼:
sayGreeting("Hello!")

现在很明显,您在说问候。换句话说,函数名称本身可以更清楚地描述您在做什么。因此,sayGreeting("Hello!")say(greeting: "Hello!")更可取,因为函数执行的关键操作应由其名称描述,而不是降级为参数名称并具有次要重要性。

但这仅对第一个论点有效。假设您想添加一个名称,就像已经完成的那样。在像C这样的语言中,您根本没有任何外部参数名称,您可以这样写:
void sayGreetingToName(char * greeting, char * person) { ...

并这样称呼它:
sayGreetingToName("Hello", "Dave");

可以,但是当您有重载的函数或默认值时,它们很快就会崩溃,而C中都没有。
func sayGreetingToName(greeting: String, name: String? = nil) {
    if let name = name {
        print("\(greeting), \(name)!")
    }
    else {
        print("\(greeting)!")
    }
}

然后将其称为:
sayGreetingToName("Hello", "Dave")

看起来基本上可以,但是:
sayGreetingToName("Hello")

看起来很荒谬,因为函数名称表明您提供的是名称,但没有提供。

因此,如果您编写:
func sayGreeting(greeting: String, toName: String? = nil) {
    if let name = toName {
        print("\(greeting), \(name)!")
    }
    else {
        print("\(greeting)!")
    }
}

您可以通过两种方式调用它:
sayGreeting("Hello")
sayGreeting("Hello", toName: "Dave")

一切看起来都很清晰。

综上所述,这种编写风格的思想是函数名称本身应包含第一个参数名称包含的任何信息,但将其扩展到后续参数没有意义。因此,默认情况下,第一个没有外部名称,其余的都具有。该函数始终都在说问候,因此该函数名应该是固有的(因此不能通过坚持第一个参数的外部名称来复制),但是它可能是也可能不是在说到一个特定的名称,以便信息不应出现在函数名称中。

它还使您基本上可以像读取英语一样来读取函数调用,因为名称和参数现在大致按正确的顺序执行:
sayGreeting("Hello", toName: "Dave")



一旦习惯了,它就是一个很好的样式。

07-24 09:50
查看更多