2021/4/3 : Swift,Dart : Swiftの関数の引数がconstantである点について

https://docs.swift.org/swift-book/LanguageGuide/Functions.html

In-Out Parameters

Function parameters are constants by default.

Swiftの関数のパラメータはデフォルトでは定数(letで宣言されているのと同じ)である。

 

//Swift
//↓arguementLabelとparameterNameを使うパターン。2つの使い分けがごっちゃになりやすいが、
//呼び出し時に使うのがargumentLabel、関数定義内(ボディ内)で使うのがparameterName。
//argumentLabelが1番目、parameterNameが2番目、型指定が3番目。これでワンセット。
/*
func someFunction(al1 pn1: Int,al2 pn2:Int) {
    // In the function body, parameterName refers to the argument value
    // for that parameter.
    //print(parameterName)
    print(pn1*pn2)
}

someFunction(al1:4,al2:9 )//36

 


(1)ということでSwiftでは関数ボディ内でパラメータaに代入しようとするとコンパイルエラーが発生する。↓

//Swift
func someFunc(a:Int){
    a=100 //エラー、Cannot assign to value: 'a' is a 'let' constant
    print(a)
}

someFunc(a:10)

 


(2)Dartの場合下記のコードでエラーは出ない。

//Dart

void someFunc(int a){
  a=100;
  print(a);
}

void main(){
  someFunc(10);//100
}

 


(3)ただSwiftでもアーギュメントにclassインスタンスを渡してボディ内でフィールドに値を代入してもエラーは発生しない。Swiftのclassは参照型なので、アーギュメントとしてsomeFuncForClsに渡したsomCls1のfieldの値も3に変わっている。

//Swift

class SomeCls{
    var field:Int=0
}

func someFuncForCls(_ a:SomeCls){
    a.field=3
    print(a.field)
}

var someCls1:SomeCls=SomeCls()
someFuncForCls(someCls1) //3
print(someCls1.field) //3

 


(4)その点はDartも同じ。

//Dart

class SomeCls{
  int field=0; 
}

void someFuncForCls(SomeCls sc){
  sc.field=200;
  print(sc.field);
}

void main(){
  SomeCls sc1=SomeCls();
  someFuncForCls(sc1); //200
  print(sc1.field); //200
}

 


(5)SwiftのStruct(構造体)の場合↓。構造体は値型なので、

letで宣言した変数、

あるいは

letで宣言した変数と同じ、関数のパラメータ

のフィールドに代入しようとするとコンパイルエラーとなる。

//Swift

struct SomeStruct{
    var field:Int=200
}

func someFuncForStruct(_ b:SomeStruct){
    b.field=5 //←コンパイルエラー、Cannot assign to property: 'b' is a 'let' constant
    print(b.field)
}

 


(3)においてSomeClsのフィールドfieldをletで宣言すれば、someFuncForCls関数内でフィールドへの代入ができなくなる。イミュータブル ということ。

//Swift

class SomeCls{
    let field:Int=0 //←letで宣言している。
}
func someFuncForCls(_ a:SomeCls){
    a.field=3 //←コンパイルエラー、Cannot assign to property: 'field' is a 'let' constant
    print(a.field)
}

 


(4)において、SomeClsのフィールドfieldをfinalで宣言すれば、someFuncForCls関数のパラメータのフィールドをし変更できなくなる。イミュータブル 。

なのでアーギュメントとして渡したsc1のfieldが意図せず変更される可能性も無くなる。

//Dart

class SomeCls {
  final int field = 0;
}

void someFuncForCls(SomeCls sc) {
  sc.field = 200; //←コンパイルエラー、'field' can't be used as a setter because it's final.
  print(sc.field);
}

void main() {
  SomeCls sc1 = SomeCls();
  someFuncForCls(sc1);
  print(sc1.field);
}

 


解説としては

https://qiita.com/koher/items/bcdbf6578b6edd1f9e0c

の解説がわかりやすい。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です