« RaspberryPi3導入:日本語設定,ネットワーク設定まで | トップページ | Swift3で文字列のsubstring »

Swift3のコーディング規約

臨時のメモ

 Swiftは面倒でも「くどい」コーディング規約が必須

swiftは古い酒(Objectve-C)を古い革袋(対話型スクリプト言語)に入れ、その革袋は穴だらけという言語なので、 思わぬ失敗を防ぐため、すこし「くどい」コーディング規約が必須です。

swiftはとても記述が面倒な言語なのです。
「あれも書かなくていい、これも省略できる」などという宣伝に踊らされてはなりません。

*文末には必ず;を付ける

swiftは行単位で解析を行う言語です。
コンパイラだとはいえ文法はシェルなどと同じいわゆるスクリプト系のもので、 決して高級言語系のものではありません。
改行を重視するのが対話型スクリプト言語の特徴です。
そのため文末のセミコロンは"省略"できます。Javascriptと同じです。

あくまで1行に1文を置く場合省略できるのであって、例えば次のような場合は 省略できません。
  a = 1 b = 1
この場合
  a = 1; b = 1
とする必要があります。;を追加するのではありません。省略できないのです。

セミコロンの省略が可能なJavascriptでも通常セミコロンの省略をしないように、 swiftでもセミコロンを省略すべきではありません。

swift言語そのものはセミコロンで文の終わりとする確実な方向に進化すべきです。

*演算子は必ず前後に空白を入れる

  a=0;            // NG
  a = 0;          // OK
  if( a==0 ){...  // NG
  if( a == 0 ){.. // OK
==ならコンパイラは通るが!=だと通らないなどデタラメを極める文法でイライラしないため 予めこういう習慣をつけておく必要があります。

*変数定義では必ず型名を入れる

関数の戻りを受ける場合、型を書かないと、ソース上離れた場所でエラーが 発生する可能性があります。またバージョンが変わると、エラーになることもあります。
必ず型を記述すべきです。
これは習慣づける必要があります。その為、全ての変数宣言で型を記述します。

let s        = "abc";    // NG
let s:String = "abc";    // OK
let x        = ClassX(); // NG
let x:ClassX = ClassX(); // OK
let x:ClassX = .();      // 将来のswift
let a                  = Array<String>(); // NG
let a:[String]         = []; // OK 
let m                  = Dictionary<String,ClassX?>(); // NG
let m:[String:ClassX?] = [:];// OK 
let r                      = "abcdef".rangeOfString("def");// 絶対禁止!
let r:Index<String.Index>? = "abcdef".rangeOfString("def");// OK

*guard-let-else{}文によるアンラップ処理(撤回)

この項は撤回です。
アンラップ処理は混乱の元と判断しました。
intなどを除いて全てをオプショナルにするのが混乱を防止するのには良い。
もちろん一番望ましいのはこんな言語は使わないことです。

ローカル変数は出来るだけオプショナルを避け、引数で受け取る値や、呼び出した関数の戻り値が オプショナルの場合、guard-let-else{}構文を用いてアンラップした変数を使います。
記述形式は"guard"の次の行に"else"を置きます。1行に書くことは禁止です。

   func X(str_:String?){
      guard let _str:String = str_  // _strがオプショナルでないことに注意
      else { return; }//アンラップ失敗
      ... _strを使用
      guard let _val:Int = getValue(_str) // getValueがInt?を返すとして
      else { return; }//アンラップ失敗
      ... _valを使用
      }
swiftは他の言語のような例外処理機構を持ちませんのでnilコケを上位でキャッチして なんとか処理を続けるといったことはできません。
例外処理機構と誤解されることもあるようですがdo-try-catchはあくまでエラー戻り値の別口 であって、例外処理ではありません。
各場所で細かく利用者がチェックし nilコケを避けなければなりません。とてつもなく面倒な言語なのです。こんな 超低級言語は地上から無くなるべきです。ひどすぎます。

先に述べた「必ず型名を入れる」という習慣がない場合次のような無意味な記述を行いがちなので注意が必要です。

   func X(str_:String?){
      guard let _str = str_
      else { return; }
      ...
      guard let _val = getValue(_str)
      else { return; }
      ...
      }
この例では2つのローカル変数はオプショナルになっており、guardは全く働きません。

*式が複数行に渡る場合は必ず括弧でくくる

swiftは改行を文の終わりとしたがる傾向が強く、例えば次の文は2つの文と解釈され、 コンパイルエラーとはならず動作がおかしくなります。

   let a = func1()
          +func2();
   // a = func1();
   // +func2();     という2つの文と解釈される
これを避ける為、複数行からなる式は必ず括弧でくくります。
   let a =( func1()
           +func2() );
これで少なくともコンパイルエラーにすることはでき、最悪の事態はさけられます。

swiftは文の終わりにセミコロンが要らないという大したメリットの ないことのために、とてつもなく危険な言語となっているのです。
面倒ですが堅牢なプログラムのためにはこの括弧でくくる作業はとても重要です。

*要素名を付けないタプルは使用禁止

危険な甘い誘惑です。

*関数の戻り値の型は引数並びとは別の行に置く

関数が戻り値を持つものか、それがどういう型かは一目で分からねばなりません。
その為、引数並びとは別の行に、->を関数名と位置を揃えて書きます。

   static public func substring(str_:String, start_:Int, end_:Int)
                      -> String{
      //...
      }

*省略できるなら省略すべきもの

式の右辺で型を.で省略可能な場合は省略すべきです。
例えばenumの代入などです。

   enum E { case
      E1
     ,E2
     ,E3
      }
   let ee:E = .E2; // E.E2とは書かない

 おすすめ規約

次の規約もおすすめです。(あくまでおすすめ)

*インデントは3文字分、{の次の文から下がり}の次の文から戻る
ラベルは1インデント分戻します。

*ローカル変数は頭に_、引数は最後に_を付ける。

|

« RaspberryPi3導入:日本語設定,ネットワーク設定まで | トップページ | Swift3で文字列のsubstring »

トラックバック


この記事へのトラックバック一覧です: Swift3のコーディング規約:

« RaspberryPi3導入:日本語設定,ネットワーク設定まで | トップページ | Swift3で文字列のsubstring »