一尘不染

为什么函数调用在Swift中需要参数名称?

swift

我在课堂上有这个功能:

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

我尝试使用此函数来调用该函数:

var multResult = calculator.multiply(9834, 2321)

问题是编译器希望它看起来像这样:

var multResult = calculator.multiply(9834, factor2: 2321)

为什么第一个会导致错误?


阅读 265

收藏
2020-07-07

共1个答案

一尘不染

Swift 2.0更新 :现在,默认情况下,函数的功能与方法相同,并且对于两种方法而言:

  • 第一个参数没有外部名称;和
  • 其他参数的外部名称与内部名称相同。

除此之外,下面的规则仍然适用,只是#速记语法已消失。


这是一个更一般的答案:函数在类之外定义为真函数时以及在定义为方法时的行为会有所不同。而且,初始化方法有一个特殊的规则。


功能

假设您定义了以下内容:

func multiply1(f1: Double, f2: Double) -> Double {
    return f1 * f2
}

这里的参数名称仅在函数 本地 ,并且在调用函数时不能使用:

multiply1(10.0, 10.0)

如果要在调用函数时强制使用命名参数,则可以。在每个参数声明的 外部
加上前缀。在这里,的外部名称f1f1param,对于f2,我们使用速记(在该速记之前加上前缀),#以指示本地名称也将用作外部名称:

func multiply2(f1param f1: Double, #f2: Double) -> Double {
    return f1 * f2
}

然后,必须使用命名参数:

multiply2(f1param: 10.0, f2: 10.0)

方法

方法不同。正如您所发现的,默认情况下,除第一个参数外的所有参数都被命名。假设我们有这个,并考虑该multiply1方法:

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)

最后,您可以_为以下其他参数声明一个外部名称,表示您要在不使用命名参数的情况下调用方法,如下所示:

calc.multiply3(10.0, 10.0)

互操作性说明: 如果class Calc@objc注释前面加上前缀,则可以在Objective-
C代码中使用它,并且它等效于此声明(请查看参数名称):

@interface Calc
- (double)multiply1:(double)f1 f2:(double)f2;
- (double)multiply2WithF1param:(double)f1 f2:(double)f2;
- (double)multiply3:(double)f1 :(double)f2;
@end

初始化方法

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

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

let c1 = Calc(start: 6)
let c2 = Calc("6")

在这里,您必须指定start:接受的重载Int,但对于接受的重载则必须将其忽略String

互操作性说明: 此类将被导出到Objective-C,如下所示:

@interface Calc
- (instancetype)initWithStart:(NSInteger)start __attribute__((objc_designated_initializer));
- (instancetype)init:(NSString *)start __attribute__((objc_designated_initializer));
@end

关闭

假设您定义了这样的闭包类型:

typealias FancyFunction = (f1: Double, f2: Double) -> Double

参数名称的行为与方法中的名称非常相似。除非您将外部名称显式设置为_,否则在调用闭包时必须为参数提供名称。

例如,执行关闭:

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

根据经验:即使您不喜欢它们,也应该至少在两个参数具有相同类型的情况下尝试继续使用命名参数,以消除歧义。我还要指出,也至少要命名all
IntBooleanparameters 很好。

2020-07-07