What's the _ underscore representative of in S

2020-01-24 03:38发布

问题:

In the reference section of Apple's docs there's lots of instances of this sort of thing:

func runAction(_action: SKAction!)

The Objective-C 'equivalent' of this is:

- (void)runAction:(SKAction *)action

It strikes me that it's probably important that (in the Swift reference) there's a space after the underscore and "action" is written in italics.

But I can't figure out what this is trying to convey. So perhaps the question is... is there a reference for the conventions used in the references?

-- here's the page I'm referencing in this reference to the underscore use: https://developer.apple.com/documentation/spritekit/sknode#//apple_ref/occ/instm/SKNode/runAction

Update

Swift 3 has made some changes to how function/method parameter names and argument labels are used and named. This has ramifications on this question and its answer. @Rickster does an amazing job of answering a different question about _underscores in functions that clears much of this up, here: Why do I need underscores in swift?

回答1:

Both answers were correct but I want to clarify a little bit more.

_ is used to modify external parameter name behavior for methods.

In Local and External Parameter Names for Methods section of the documentation, it says:

Swift gives the first parameter name in a method a local parameter name by default, and gives the second and subsequent parameter names both local and external parameter names by default.

On the other hand, functions by default don't have external parameter names.

For example, we have this foo() method defined in class Bar:

class Bar{
    func foo(s1: String, s2: String) -> String {
        return s1 + s2;
    }
}

When you call foo(), it is called like bar.foo("Hello", s2: "World").

But, you can override this behavior by using _ in front of s2 where it's declared.

func foo(s1: String, _ s2: String) -> String{
    return s1 + s2;
}

Then, when you call foo, it could be simply called like bar.foo("Hello", "World") without the name of the second parameter.

Back to your case, runAction is a method because it's associated with type SKNode, obviously. Thus, putting a _ before parameter action allows you to call runAction without an external name.

Update for Swift 2.0

Function and method now work the same way in terms of local and external argument name declaration.

Functions are now called by using external parameter name by default, starting at 2nd parameter. This rule only applies to pure Swift code.

So, by providing an _ in front of a function, the caller won't have to specify external parameter name, just like what you would do for a method.



回答2:

The underscore is a general token used to indicate a discarded value.

In this specific case, it means that the function will be invoked as runAction(argument) instead of runAction(action:argument)

In other contexts it has other similar meaning, e.g. in:

for _ in 0..<5 { ... }

It means that we merely want to execute the block 5 times and we don't care about the index within the block.

In this context:

let (result, _) = someFunctionThatReturnsATuple()

It means that we don't care what the second element of the tuple is, only the first.



回答3:

An identifier in front of parameter declaration defines an external parameter name. This is the name that must be provided by the caller when calling the function:

func someFunction(externalParameterName localParameterName: Int)

Swift provides an automatic external name for any defaulted parameter you define, if you do not provide an external name yourself. Using an underscore for the external parameter name opts out from this behavior:

You can opt out of this behavior by writing an underscore (_) instead of an explicit external name when you define the parameter.

You can read more about this behavior in the section on External Names for Parameters with Default Values here.



回答4:

Since Swift 3 all argument labels are required by default.

You can force an IDE to hide an argument label with _.

func foo(a: String) {
}

func foo2(_ a: String) {
}

called foo(a: "abc") and foo2("abc")

Note: This can be used only when a is the (external) argument label and (internal) variable name at the same time. It's equivalent - func foo(a a: String) won't accept the _.

Why is Apple using it?

You can see Apple is using it across the API. Apple's libraries are still written in Objective-C (if not, they share the same function names anyway, which were designed for Objective-C syntax)

Functions like applicationWillResignActive(_ application: UIApplication) would have redundant parameter name application, since there is already the application in it's function name.

Your example

func runAction(_ action: SKAction!) would be called without it's _ mark like runAction(action:). The parameter name action would be redundant since there is already one in the function name. That's the purpose and why it's there.



回答5:

I think this forces a convention in Swift that makes it read closer to objective-c, which matches cocoa conventions better. In objc you don't (externally) name your first parameter. Instead, by convention you usually include the external name in the latter part of the method name like this:

- (void)myFancyMethodWithFirstName:(NSString *)aFirstName lastName:(NSString *)aLastName;

[someInstance myFancyMethodWithFirstName:@"John" lastName:@"Doe"];

To make Swift api calls consistent with objc you will want to suppress the external parameter name of the first param.

func myFancyMethodWithFirstName(_ firstName:String, lastName:String);

someInstance.myFancyMethodWithFirstName("John", lastName:"Doe")


回答6:

Actually, there is a difference between the real code used to define a method and the method declaration in Apple's docs. Let's take UIControl's - addTarget:action:forControlEvents: method for example, the real code is:

But in docs, it appear like this (notice _ before target):

In real code, _ is used to make the second or subsequent parameter's external name not appear when a method is called, while in docs, _ before a parameter's local name indicates that when you call a method or a function, you should not provide an external name.

There's no external name when a function is called by default unless you provide your own or add # before (without whitespace) a parameter's local name, for example, this is how we use dispatch_after:

And in docs, it appear like this (notice three _):

The convention of function's declaration is just the same as I have described for method.



回答7:

Just more visually.

As you can see the _ just make omit a local parameter name or not.