Swift: отсутствует метка аргумента "xxx" в вызове

func say(name:String, msg:String) {
    println("\(name) say \(msg)")
}

say("Henry","Hi,Swift")  <---- error because missing argument label 'msg' in call

Мне нужно использовать

   say("Henry",msg:"Hi,Swift")

Почему? Если я помещаю более двух переменных в func, поэтому мне нужно написать имя var вместо первого var, когда я вызываю это func
Это действительно проблема, и я не вижу объяснений в учебнике iBook Swift.

Ответ 1

Одна из возможных причин состоит в том, что это фактически метод. Методы очень подлые, они выглядят так же, как обычные функции, но они не действуют одинаково, давайте посмотрим на это:

func funFunction(someArg: Int, someOtherArg: Int) {
    println("funFunction: \(someArg) : \(someOtherArg)")
}

// No external parameter
funFunction(1, 4)

func externalParamFunction(externalOne internalOne: Int, externalTwo internalTwo: Int) {
    println("externalParamFunction: \(internalOne) : \(internalTwo)")
}

// Requires external parameters
externalParamFunction(externalOne: 1, externalTwo: 4)

func externalInternalShared(#paramOne: Int, #paramTwo: Int) {
    println("externalInternalShared: \(paramOne) : \(paramTwo)")
}

// The '#' basically says, you want your internal and external names to be the same

// Note that there been an update in Swift 2 and the above function would have to be written as:

func externalInternalShared(paramOne paramOne: Int, #paramTwo: Int) {
    print("externalInternalShared: \(paramOne) : \(paramTwo)")
}

externalInternalShared(paramOne: 1, paramTwo: 4)

Теперь вот забавная часть, объявляющая функцию внутри класса, и это уже не функция... это метод

class SomeClass {
    func someClassFunctionWithParamOne(paramOne: Int, paramTwo: Int) {
        println("someClassFunction: \(paramOne) : \(paramTwo)")
    }
}

var someInstance = SomeClass()
someInstance.someClassFunctionWithParamOne(1, paramTwo: 4)

Это часть дизайна поведения для методов

Apple Docs:

В частности, Swift дает первое имя параметра в методе имя локального параметра по умолчанию и дает по умолчанию второй и следующий имена параметров как локальные, так и внешние имена параметров. Это соглашение соответствует типичному соглашению об именах и вызовах, с которым вы будете знакомы, при написании методов Objective-C, а также для выражения выразительных методов без необходимости определять имена параметров.

Обратите внимание на автозаполнение: enter image description here

Ответ 2

Это просто влияние языка Objective-C. При вызове метода первый параметр метода не должен быть явно помечен (как в Objective-C он эффективно "помечен" именем метода). Однако всем следующим параметрам требуется имя для их идентификации. Они также могут использовать (необязательное) локальное имя для использования внутри самого метода (см. Ссылку Jiaaro в комментариях выше).

Ответ 3

Это причуда в компиляторе. Функции (которые не являются членами класса) и методы класса имеют разные значения по умолчанию в отношении именованных параметров. Это согласуется с поведением названных параметров в objective-C (но не имеет смысла для кого-то нового для быстрого, без опыта работы с objective-C).

Здесь ссылка на язык должна указывать на именованные параметры для функций (в частности, параметры, где внешнее имя параметра не задано, а параметр не имеет значения по умолчанию)

Однако эти имена параметров используются только в теле самой функции, а не может использоваться при вызове функции. Эти типы имен параметров называются локальными именами параметров, поскольку они доступны только для использования в теле функций.

Информацию о методах класса см. в ответе Logan.

Ответ 4

Обновление Swift 3.0:

В swift 3.0 методы с одним именем параметра для каждого входа необходимы, чтобы иметь это имя параметра как часть вызова функции. Поэтому, если вы определите функцию, подобную этой

func say(name:String, msg:String) {
    print("\(name) say \(msg)")
}

Ваш вызов функции должен быть таким

self.say(name: "Henry",msg: "Hi,Swift")

Если вы хотите иметь английский, как читаемые метки функций, но не хотите изменять имя входного параметра, вы можете добавить метку перед именами параметров, например,

func say(somethingBy name:String, whoIsActuallySaying msg:String) {
    print("\(name) say \(msg)")
}

Затем назовем это следующим образом

self.say(somethingBy: "Henry",whoIsActuallySaying: "Hi,Swift")