私はクラスにこの関数を持っています:
func multiply(factor1:Int, factor2:Int) -> Int{
return factor1 * factor2
}
私はこれを使用して関数を呼び出そうとします:
var multResult = calculator.multiply(9834, 2321)
問題は、コンパイラが次のように見えることを望んでいることです。
var multResult = calculator.multiply(9834, factor2: 2321)
最初のものがエラーを引き起こすのはなぜですか?
Swift 2.0)の更新:関数はデフォルトでメソッドと同じように動作し、両方に対して:
それ以外は、#
の短縮形構文がなくなったことを除いて、以下の規則が引き続き適用されます。
より一般的な答えは次のとおりです。クラス外の真の関数として定義された場合と、メソッドとして定義された場合の関数の動作は異なります。さらに、initメソッドには特別なルールがあります。
これを定義するとします:
func multiply1(f1: Double, f2: Double) -> Double {
return f1 * f2
}
パラメーター名は、関数に対してのみlocalであり、関数を呼び出すときに使用できません。
multiply1(10.0, 10.0)
関数を呼び出すときに名前付きパラメーターを使用することを強制する場合は、できます。各パラメータ宣言の前にexternal名を付けます。ここでは、f1
の外部名はf1param
であり、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
}
}
次に、2番目(および、もしあれば)のパラメーターの名前を使用する必要があります。
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")
ここでは、Int
を受け入れるオーバーロードにstart:
を指定する必要がありますが、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)
}
経験則として:たとえそれらを嫌いでも、少なくとも2つのパラメーターの型が同じであれば、それらを明確にするために、おそらく名前付きパラメーターを使用し続けることをお勧めします。また、少なくともすべてのInt
パラメーターとBoolean
パラメーターに名前を付けるのも良いと主張します。
関数呼び出しのパラメーター名はキーワード名と呼ばれ、Smalltalk言語にまでさかのぼります。
クラスとオブジェクトは他の場所から再利用されたり、非常に大規模で複雑なシステムの一部を形成したりすることが多く、一度にアクティブなメンテナンスを行うことはできません。
これらの状況では、開発者が締め切りのプレッシャーにさらされているとコードが最終的に唯一のドキュメントになることが多いため、コードの明快さと読みやすさを改善することは非常に重要です。
各パラメーターに説明的なキーワード名を付けると、メンテナーは、関数コード自体を深く掘り下げるのではなく、関数呼び出しを一見することで、関数呼び出しの目的をすばやく確認できます。パラメーターの暗黙の意味を明示的にします。
関数呼び出しのパラメーターにキーワード名を採用する最新の言語は Rust(link) -「非常に高速で実行され、セグメンテーション違反を防ぎ、スレッドの安全性を保証するシステムプログラミング言語」と説明されています。
稼働率の高いシステムには、より高いコード品質が必要です。キーワード名を使用すると、開発チームと保守チームはandを回避して、間違ったパラメーターを送信したり、パラメーターを誤って呼び出したりすることによるエラーをキャッチできます。
言葉遣いも簡潔でも構いませんが、Smalltalkerは簡潔で無意味なものよりも、言葉遣いがあり説明的なものを好みます。彼らはIDEがそのようなタイピングの大部分を彼らのために行うので、彼らはそうする余裕があります。
サンプルコードでcalculator.multiply()
を使用したため、この関数はcalculator
オブジェクトのメソッドであると想定しています。
Swiftはobjective-cから多くのものを継承しており、これはそのうちの1つです:
Objective-Cで(仮に)行う場合:
[calculator multiply:@9834 factor2:@2321];
Swiftと同等 は次のとおりです。
calculator.multiply(9834, factor2:2321);
「乗算」関数はメソッドであり、Objective-cと同様に、メソッドのパラメーターは名前の一部です。
たとえば、これを行うことができます。
class Calculator {
func multiply(factor1:Int, factor2:Int) -> Int{
return factor1 * factor2
}
func multiply(factor1:Int, factor2:Int, factor3:Int) -> Int{
return factor1 * factor2 * factor3
}
}
ここには、multiply(factor2)とMultiply(factor2 factor3)という名前の異なる2つのメソッドがあります。
このルールはメソッドにのみ適用されます。これをクラス外の関数のように宣言する場合、関数呼び出しはパラメーター名を必要としません。
値を返さない引数としてメソッドを渡すことに関する注意:
func refresh(obj:Obj, _ method: (Obj)->Void = setValue) {
method(element)
}
func setValue(obj:Obj){
obj.value = "someValue"
}
refresh(someObj,setValue)