Methods 为什么函数调用需要Swift中的参数名?

Methods 为什么函数调用需要Swift中的参数名?,methods,swift,named-parameters,Methods,Swift,Named Parameters,我在一个类中有这个函数: func multiply(factor1:Int, factor2:Int) -> Int{ return factor1 * factor2 } 我尝试使用以下方法调用函数: var multResult = calculator.multiply(9834, 2321) 问题是编译器希望它看起来更像这样: var multResult = calculator.multiply(9834, factor2: 2321) calc.multipl

我在一个类中有这个函数:

func multiply(factor1:Int, factor2:Int) -> Int{
    return factor1 * factor2
}
我尝试使用以下方法调用函数:

var multResult = calculator.multiply(9834, 2321)
问题是编译器希望它看起来更像这样:

var multResult = calculator.multiply(9834, factor2: 2321)
calc.multiply3(10.0, 10.0)
typealias FancyFunction = (f1: Double, f2: Double) -> Double

为什么第一个会导致错误

因为您在示例代码中使用了
calculator.multiply()
,所以我假设此函数是
calculator
对象的方法

Swift从objective-c继承了很多东西,这就是其中之一:

在objective-c中,您将(假设)执行以下操作:

最重要的是:


针对Swift 2.0的更新:现在函数的行为与方法相同,默认情况下,对于这两种方法:

  • 第一个参数没有外部名称;及
  • 其他参数的外部名称与内部名称相同
除此之外,下面的规则仍然适用,除了
#
速记语法现在已经消失


这里有一个更一般的答案:当定义为类外的真函数时,函数的行为与定义为方法时不同。此外,init方法有一个特殊的规则


功能 假设您定义了以下内容:

func multiply1(f1: Double, f2: Double) -> Double {
    return f1 * f2
}
这里的参数名称仅为函数的本地,在调用函数时不能使用:

multiply1(10.0, 10.0)
如果要在调用函数时强制使用命名参数,可以。在每个参数声明前面加上其外部名称。这里,
f1
的外部名称是
f1param
,对于
f2
,我们使用缩写,在前缀处加上
#
,表示本地名称也将用作外部名称:

func multiply2(f1param f1: Double, #f2: Double) -> Double {
    return f1 * f2
}
然后,必须使用命名参数:

multiply2(f1param: 10.0, f2: 10.0)

方法 方法不同。默认情况下,除第一个参数外,所有参数都已命名,如您所发现的。假设我们有这个,并考虑<代码>乘法1方法:

class Calc {
    func multiply1(f1: Double, f2: Double) -> Double {
        return f1 * f2
    }
    func multiply2(f1param f1: Double, f2: Double) -> Double {
        return f1 * f2
    }
    func multiply3(f1: Double, _ f2: Double) -> Double {
        return f1 * f2
    }
}
然后,必须使用第二个(以及以下,如果有的话)参数的名称:

let calc = Calc()
calc.multiply1(1.0, f2: 10.0)
您可以通过为第一个参数提供外部名称(如函数)强制使用命名参数(如果要使用与其本地名称相同的外部名称,则可以在其本地名称前面加上
#
)。然后,你必须使用它:

calc.multiply2(f1param: 10.0, f2: 10.0)
最后,您可以为以下其他参数声明一个外部名称
,表示您希望在不使用命名参数的情况下调用方法,如下所示:

var multResult = calculator.multiply(9834, factor2: 2321)
calc.multiply3(10.0, 10.0)
typealias FancyFunction = (f1: Double, f2: Double) -> Double
互操作性注意:如果您在
类Calc
前面加上
@objc
注释,那么您可以从Objective-C代码中使用它,它与此声明等效(查看参数名称):


初始化方法
init
方法的规则略有不同,默认情况下,所有参数都有一个外部名称。例如,这是有效的:

class Calc {
    init(start: Int) {}
    init(_ start: String) {}
}

let c1 = Calc(start: 6)
let c2 = Calc("6")
在这里,您必须为接受
Int
的重载指定
start:
,但对于接受
字符串的重载必须忽略它

互操作性注意:此类将导出到Objective-C,如下所示:

var multResult = calculator.multiply(9834, factor2: 2321)
calc.multiply3(10.0, 10.0)
typealias FancyFunction = (f1: Double, f2: Double) -> Double

闭包 假设您定义的闭包类型如下:

var multResult = calculator.multiply(9834, factor2: 2321)
calc.multiply3(10.0, 10.0)
typealias FancyFunction = (f1: Double, f2: Double) -> Double
参数名称的行为与方法中的名称非常相似。在调用闭包时,必须为参数提供名称,除非将外部名称显式设置为u

例如,执行闭包:

fund doSomethingInteresting(withFunction: FancyFunction) {
    withFunction(f1: 1.0, f2: 3.0)
}

作为经验法则:即使您不喜欢它们,您也应该尝试至少在两个参数具有相同类型时继续使用命名参数,以便消除歧义。我还认为,至少命名所有
Int
Boolean
参数也很好。

因为“乘法”函数是一种方法,与Objective-c一样,方法中的参数也是名称的一部分

例如,您可以这样做

class Calculator {

    func multiply(factor1:Int, factor2:Int) -> Int{
        return factor1 * factor2
    }

    func multiply(factor1:Int, factor2:Int, factor3:Int) -> Int{
        return factor1 * factor2 * factor3
    }

}
这里有两种不同的方法,具有不同的名称:乘法(factor2)和乘法(factor2 factor3)


此规则仅适用于方法,如果将其声明为类外的函数,则函数调用不需要参数名。

原因是历史原因。这就是它在Smalltalk中的工作方式,它在后代中存活下来。斯奎克,目标C,斯威夫特

幼稚的语言(Squeak、Scratch和Blockly)坚持使用它,因为刚开始的程序员往往会在算术和参数顺序上挣扎。这就是Smalltalk这样做的最初原因。我不知道为什么ObjC和Swift决定通过该公约,但他们确实通过了


函数调用中的参数名称为关键字名,它们可以追溯到Smalltalk语言

类和对象通常从其他地方重复使用,或者构成非常大的复杂系统的一部分,并且在很长一段时间内不会有积极的维护注意

在这些情况下,提高代码的清晰性和易读性非常重要,因为当开发人员面临截止日期压力时,代码往往最终成为唯一的文档

为每个参数指定一个描述性的关键字名称,使维护人员能够通过浏览函数调用快速了解函数调用的目的,而不是深入研究函数代码本身。它使参数的隐含含义变得明确

在函数调用中为参数采用关键字名称的最新语言被描述为“一种运行速度极快、防止segfaults并保证线程安全的系统编程语言”

高正常运行时间系统需要更高的代码质量。关键字名称使开发和维护团队有更多的机会避免和捕获错误,因为发送错误的参数或无序调用参数

它们可以是罗嗦或简练的,但小人更喜欢罗嗦和描述性的,而不是简练和无意义的。他们可以负担得起