Invalid Redeclaration of function in Swift

2019-05-29 05:43发布

问题:

I'm trying to write some helper functions and am getting an 'Invalid Redeclaration' error of some similar methods. If anyone can explain why these methods collide I would be very thankful.

func CGRectModify(rect: CGRect, x: CGFloat) -> CGRect {
    return CGRectMake(x, rect.origin.y, rect.size.width, rect.size.height)
}

func CGRectModify(rect: CGRect, y: CGFloat) -> CGRect {
    return CGRectMake(rect.origin.x, y, rect.size.width, rect.size.height)
}

func CGRectModify(rect: CGRect, width: CGFloat) -> CGRect {
    return CGRectMake(rect.origin.x, rect.origin.y, width, rect.size.height)
}

func CGRectModify(rect: CGRect, height: CGFloat) -> CGRect {
    return CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, height)
}

I would think that because the second parameter has a different external name, the method would be understood to have a different signature. It seems that is not the case.

I've been using Apple's doc for reference, but in the section of Local and External Parameter Names for Methods I could not find my answer. Any input is much appreciated.

回答1:

The rule of "automatic external parameter names" for functions are different from methods.

Swift applies different rules depends on the type of callables.

  1. Functions/Closures → document

    No "automatic external parameter names" are performed.

    func f(x:Int, y:Int) { /* ... */ }
    let c =  { (x:Int, y:Int) -> Void in /* ... */ }
    
    f(1, 2)
    c(1, 2)
    
  2. Initializers → document

    "automatic external parameter names" are the default for every parameters.

    class Foo {
        init(x:Int, y:Int) { /* ... */ }
    }
    
    let foo = Foo(x: 1, y: 2)
    
  3. Methods → document

    "automatic external parameter names" except for the first parameter.

    extension Foo {
        func bar(x:Int, y:Int) { /* ... */ }
    }
    
    foo.bar(1, y:2)
    
  4. Subscript → document missing?

    No "automatic external parameter names" are performed.

    extension Foo {
        subscript(x:Int, y:Int) -> Void {
            get { /* ... */ }
        }
    }
    
    foo[1, 2]
    

And a special rule for ...

  • Default Values

    func fz(x:Int, y:Int, z:Int = 1) { /* ... */ }
    
    fz(1, 1, z: 1)
    

Of course you can override these default behaviors using:

  • _ name:Type: disable "automatic external parameter names"
  • #name:Type: force "automatic external parameter names"
  • externalName internalName:Type: explicit external name


回答2:

This actually looks like a bug in the documentation. In the section I originally linked to, Local and External Parameter Names for Methods the follow explanation is written.

This default behavior effectively treats the method as if you had written a hash symbol (#) before the numberOfTimes parameter:

func incrementBy(amount: Int, #numberOfTimes: Int) { 
      count += amount * numberOfTimes
}

This is not the case. When I do add the hash symbol (#) to my second parameter, the compiler error does not occur.

func CGRectModify(rect: CGRect, #height: CGFloat) -> CGRect {
    return CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, height)
}