【问题标题】:Multiple functions with the same name多个同名函数
【发布时间】:2014-12-29 13:44:38
【问题描述】:

我是 Swift 新手,我一直在阅读一些教程,其中许多教程不止一次定义了同名的函数。

我已经习惯了其他无法做到这一点的编程语言,否则会引发错误。

因此,我检查了官方的Swift Manual 并检查了override 关键字,看看我能从中得到什么,但我仍然无法理解以下代码:

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 10
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestCell")

    cell.textLabel?.text = "Row #\(indexPath.row)"
    cell.detailTextLabel?.text = "Subtitle #\(indexPath.row)"

    return cell
}

从我可以看到函数 tableView 在第 1 行和第 5 行中设置,我注意到的唯一区别是第一个 tableView 函数返回一个 Int 而第二个返回一个 Object (UITableViewCell)。

在这种情况下,我从结果中看到第二个函数没有覆盖第一个函数。

这是什么意思,为什么可以多次定义同名的函数而不覆盖它?

【问题讨论】:

    标签: swift


    【解决方案1】:

    如果它们具有不同的类型,或者如果它们可以通过它们的外部参数参数标签来区分,则可以使用相同的名称定义两个函数。函数的类型由括号中的参数类型组成,后面是->,后面是返回类型。请注意,参数标签不是函数类型的一部分。 (但请参阅下面的更新。)

    例如,以下函数同名且类型为(Int, Int) -> Int

    // This:
    func add(a: Int, b: Int) -> Int {
        return a + b
    }
    
    // Is the same Type as this:
    func add(x: Int, y: Int) -> Int {
        return x + y
    }
    

    这将产生编译时错误 - 将标签从 a:b: 更改为 x:y: 不会区分这两个函数。 (但请参阅下面的更新。)

    以Web先生的功能为例:

    // Function A: This function has the Type (UITableView, Int) -> Int
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { ... }
    
    // Function B: This function has the Type (UITableView, NSIndexPath) -> UITableViewCell
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { ... }
    
    // Function C: This made up function will produce a compile-time error because
    // it has the same name and Type as Function A, (UITableView, Int) -> Int:
    func tableView(arg1: UITableView, arg2: Int) -> Int { ... }
    

    上面的函数 A 和函数 B 不冲突,因为它们属于不同的类型。 上面的do函数A和函数C冲突,因为它们的类型相同。如果类型保持不变,更改参数标签并不能解决冲突。 (请参阅下面的更新。)

    override 完全是一个不同的概念,我认为其他一些答案涵盖了它,所以我会跳过它。

    更新:我上面写的有些内容是不正确的。确实,函数的参数标签不是其类型定义的一部分,但它们可以用来区分具有相同类型的两个函数,只要该函数具有不同的外部标签,以便编译器可以分辨出哪个调用它时尝试调用的函数。示例:

    func add(a: Int, to b: Int) -> Int {    // called with add(1, to: 3)
        println("This is in the first function defintion.")
        return a + b
    }
    
    func add(a: Int, and b: Int) -> Int {   // called with add(1, and: 3)
        println("This is in the second function definition")
        return a + b
    }
    
    let answer1 = add(1, to: 3)    // prints "This is in the first function definition"
    let answer2 = add(1, and: 3)   // prints "This is in the second function definition"
    

    因此,在函数定义中使用外部标签将允许编译具有相同名称和相同类型的函数。因此,您似乎可以编写多个具有相同名称的函数,只要编译器可以通过它们的类型或它们的外部签名标签来区分它们。我认为内部标签并不重要。 (但如果我错了,我希望有人能纠正我。)

    【讨论】:

    • +1 用于包含外部标签说明。我在 simd 库中找到了它,虽然很酷,但我很惊讶它被允许,所以去搜索并找到了你的答案。 public init(_ columns: [double3])public init(rows: [double3]) 都是 double3x3 的有效初始化器,并且都具有相同的类型签名。
    • 更准确地说:您会想要使用参数名称(用于内部定义)和参数标签(用于外部调用)。不是参数标签。 (如果我错了或我认为的不准确,请纠正我)
    • 看起来有更多的注意事项。也就是说,如果一个 swift 类扩展了一个 Obj-C 类,或者你用 @objc 注释了这两个函数,你将无法根据类型重载,因为选择器是相同的。相关,是否可以在扩展 objc 类时将方法排除为 objc 选择器,即与 @objc 的相反注释?
    • 回答我自己的问题:“@nonobjc”似乎可以解决问题。
    【解决方案2】:

    在 Swift 中,就像在 Objective-C 中一样,函数的参数构成了定义的一部分。没有两个函数叫tableView,一个函数叫tableView(tableView:, numberOfRowsInSection:),一个叫tableView(tableView:, cellForRowAtIndexPath:)

    【讨论】:

    • 所以错误是如果我声明 2 个具有相同名称、返回值和参数的函数,例如 func one(i:Int) -> Intfunc one(i:Int) -> Int,对吗?
    • 那将是编译时错误,项目将无法构建。
    【解决方案3】:

    您正在考虑函数重载

    摘自 Apple 文档here

    您可以通过提供重载泛型函数或初始化程序 中的类型参数有不同的约束、要求或两者兼有 泛型参数子句。当您调用重载泛型时 函数或初始化器,编译器使用这些约束来 解决要调用的重载函数或初始化程序。

    例如:

    protocol A { }
    protocol B { }
    
    class A1: A { }
    class A2: A { }
    
    class B1: B { }
    class B2: B { }
    
    func process<T: A>(value: T)
    {
        // process values conforming to protocol A
    }
    
    func process<T: B>(value: T)
    {
        // process values conforming to protocol B
    }
    

    或:

    func process(value: Int)
    {
        // process integer value
    }
    
    func process(value: Float)
    {
        // process float value
    }
    

    这种混淆很常见,尤其是当您是第一次从 Objective-C 迁移到 Swift 时。你应该阅读参数名称here

    【讨论】:

    • 谢谢,我看到了您发布的文档,还查看了来自 Apple 的 The Swift Programming Language Book。这方面的数据很少,你能解释一下吗?
    • 谢谢,我还没有了解&lt;T: A&gt;(...)这个东西。你能用一个经典的函数类型吗? (如:func process(a:Int)-&gt;Int
    • 问题中的函数与重载或泛型无关。
    【解决方案4】:

    功能不一样,它们是不同的。因为它们不采用相同的参数并返回不同的东西。如果您不了解泛型,这是简单的解释。

    【讨论】:

      猜你喜欢
      • 2023-02-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多