Swiftプログラミングノート(2016/01/05作成) †
- 追記(2017/10/20) Swift 4.0でコンパイルしてみたら、mutateしていない変数についてのwarningが出るようになったが、それ以外特に問題はなかった。
- 追記(2017/05/03) Swift 3.1になって、M_PI(円周率)をDouble.piに変えろとwarningが出るようになったので、その通りに変更した(下の例なども変更)。とするとM_Eも同様なのかと思ったら、そちらはwarningは出ない。
- 追記(2016/09/23) macOS Sierraへupdate、またXCodeもupdateしたので、Swiftのversionが3.0となった。以前作ったプログラム(Swift 2.3)をコンパイルしてみるとエラーが沢山でる。色々と変更があったようだ。以下の内容もできるだけ3.0に直した。変更があったものはエラーメッセージに出てくる場合が多いので、そのとおりに直せばよい。そのうち、頻繁に出て来たものを以下に示す。
- Arrayの定義方法の変更: 配列x(500)に初期値0.0を与える場合には、
var x = Array(count:500,repeatedValue:0.0) // version 2での定義 var x = Array(repeating:0.0, count:500) // version 3ではこうなる
- 引数も変更。Process.argumentsではダメで、CommandLine.argumentsとする。まあ、こちらの方がわかり易いが。
- componentsSeparatedByString(" ") --> components(separatedBy:" ")
- stringByExpandingTildeInPath --> expandingTildeInPath
- ***.write() --> ***.write(toFile:filePath, atomically:true,encoding:String.Encoding.utf8)とする。
- 3つのプログラムを手直して、コンパイルできるようになった。
- Arrayの定義方法の変更: 配列x(500)に初期値0.0を与える場合には、
イントロ †
- 私のMacbook AirにはXcodeおよびCommand Line Toolがインストールされている(現在はCommand Line Toolを別途インストールしなくてもいいようだ)。そのためSwiftコンパイラもterminalから利用できる。SwiftはAppleが作成したプログラム言語で、今はopen source化もされている。Mac OS, iOS用のアプリケーションが作成できる。折角なのでSwiftの勉強も兼ねて、Pythonで少し時間がかかるプログラムをSwiftに移植しようとしているが,仕様の変更, Object-C部分を使う必要などが結構あり,Swift解説本やウェブ上に載っている例でもそのまま動かないものが多い。そこで現時点で動くコードの情報をまとめている。以下はApple Swift version 2.1.1で実行した結果である(3.0にも対応させた)。
- とりあえず作りたいプログラムはterminal用なので,GUIの総合環境であるXcodeは全く使わず,直接エディタ(私はJedit)でプログラムを書き,terminal上でコンパイルしている。なので以下,GUIプログラムを作りたい方にはあまり参考にならない。Pythonプログラム1つを取りあえず移植するために勉強し、試したことをここにまとめた。その後、2つプログラムを作った。
コンパイル †
- コンパイル法はC, Fortranと同様である。ソースファイルの拡張子は.swiftである。swiftcでコンパイルする。-oで実行ファイル名を指定できる。-oを使わないと.swiftが取れたファイル名になる。実行は./実行ファイルで行う。また、最適化オプション-Oを使うと計算がかなり速くなる。
> swiftc -o test test.swift > swiftc -O test.swift > ./test
最初に重要なこと †
- 本やwebでprintln("Hello, World!")がよく出て来るが,println()は現在エラーとなる。かわりにprint()を使う。print()は改行する。改行させたくない時は,print("Hello, World!", terminator:"")としてterminatorの改行コードをとってしまう。
- 数学関数などを使う場合は,最初にDarwinかFoundationをimportする。数学関数だけならDarwinで十分だが,NSStringが必要だったらFoundationを使う。
import Foundation
- 変数はvarで定義しないとエラーとなる。推測してくれるので,値を与えて定義する場合は型を省略できる(Charは例外)。2つ目は変数をDouble型で定義していることになる。
var x: Double var x = 1.0
- 初期化しない変数は使用できない。
- コメントアウトはC++と同じく,//, /* ~ */ を使う。
- マルチステートメントは;で区切る。
- Cのように,+=, ++i等の演算が使える(Swift 3では++i,i++は使えない)
- 型変換はキャストで行えるが,予想通り行かないことも多い。Double(i)
- タプル型も用意されている。
- オプショナル型は値がない状態(nil)を持てる。?をつけて定義。アンラップする時は!を使う。NSStringを使うとアンラップが必要となるケースが生じる。
数学関数 †
- 期待するものがほぼ揃っている。三角関数はラジアン単位。
- sqrt(x), exp(x), pow(x,y), log(x), abs(x), ceil(x), floor(x)
- sin(x), cos(x), tan(x), acos(x), atan(x), cosh(x)など
- パイとeとして次の定数が定義されている:Double.pi, M_E
関数 †
- 関数は呼び出し位置より前方で定義しないとエラー。
- 関数で複数引数をとる時は外部引数名を使わないとエラーが出た。以下の例ではdist, rzero, Bが外部引数名で,呼び出す際にも必要。面倒だが,分かりやすくはなる。d,r,bは関数内のみで使われる変数。また外部引数名を関数引数名と同じにする#が以前使えたようだが,現在はエラーとなる。
func bondValence(dist d:Double, rzero r:Double, B b:Double ) -> Double { return exp((r-d)/b) } print(bondValence(dist:1.79,rzero:1.624,B:0.389)) // function call
- なお,関数の戻り値を複数にできる。上記,->の後,及びreturnの後をタプルとし,呼び出した時もタプルで受けとる。(a,b,c) = func()
実際にプログラム作る時のプラクティス †
- コマンドラインの引数を得る(version 3)
- CommandLine.arguments[]に格納されている。
- 文字列の長さは求めるのには,よく本等で見かけるcountElements(str)ではエラーになる。str.characters.countだとうまくいく。
- リテラルは""で挟む。print("Hello, World!")のように。''は不可。
- 途中でプログラム終了する場合はexit(0)を使う。
- print()内などでの式の展開は\()を使う。以下の例で\がYen markに勝手に変換される場合がありますが、\と読み替えてください。
print("x = \(x)")
- 浮動小数点数値で小数点以下の桁数を指定するにはNSStringを使う必要がある。
print("pi = \(NSString(format: "%.4f", Double.pi))")
- 配列の定義。以下はxを500要素の配列として定義して,初期値を0.0としている。初期値で型は推測できるので型指定を省略している。2つ目はString配列の定義例。
var x = Array(repeating:0.0, count:500) // version 3 var kind = Array(repeating:"", count:20) // version 3
テキストファイルの読み込み †
- テキストファイルの読み込みはNSStringを使う必要があるのでやっかいである。仕様変更でよく変わっているところでもある。そのため,実際に動いている例で示す。以下は引数にテキストファイル名を入れて実行し,そのファイル内容を読み込む例。Process.arguments[1]には1番目の引数が入る。この2行目のProcess.arguments[1]を変えれば,任意のファイルが読める。locでファイルバスが得られる。fileCotentにファイルの内容が読み込まれているが,NSStringなので,私はうまく取り扱えないので,普通のString型であるtextへ強制代入している。()!は説明が難しいが,強制的にアンラップを行っている。
var text: String let loc = NSString(string:Process.arguments[1]).stringByExpandingTildeInPath let fileContent = try? String(contentsOfFile: loc, encoding: // 次行へ続く String.Encoding.utf8) as String if fileContent == nil { print("Your specified file does not exist!") exit(0) } text = (fileContent)!
- 上記のファイル内容を処理する。以下で,行毎にString配列lines[]に代入し,lines[]を後で処理するつもり。処理によってはここのループ内に何か書けば済む場合もあるだろうが,私の場合はうまくいかなかったのでこうした。nlineには行数が入っている。
var lines = Array(repeating:"",count:500) var i = 1 text.enumerateLines { (line, stop) -> () in lines[i] = line ++i } var nline = --i
テキストファイルの書き出し †
- String変数text1に内容を詰め込んでおいて,一気に書き出す例。複数行とするために,改行記号(\n)を挟んでいる。
let text1 = "line1\nline2\nline3\n" // Stringに内容を詰め込む \nは改行 let fileName = "test.txt" let filePath = "./" + fileName // 現在のディレクトリーに do { try text1.write(toFile:filePath, atomically: true, encoding: String.Encoding.utf8) } catch { print("Failed to write to \(filePath)") }
制御構造 Cとほぼ同じ †
- if文
if 条件式 { // statement1 } else if 条件式 { // statement2 ... } else { // statement for else }
- for文: この書き方はSwift 3では使えなくなる。for~inを使えとのこと。
for i = 0; i < max; i++ { // statement }
- for文:上の例のSwift 3用書き換え
for i in 0..<max { // statement i <= maxの場合は、0...maxとする }
- for~in: Range指定 iを内部で使わない場合は変数の代わりに"_"(underscore)でもOK
for i in 1...10 { // statement }
- while文
while 条件式 { // statement (break, continue文も使える) }
- do while文
do { // statement } while 条件式
- switch文 // valueはリストもあり,breakは不要
switch 式 { case value1: // statement1 case value2: // statement2 ... default: // statement for default }
- loopからの脱出:breakは最下層ループからのみ脱出
break
- ラベル(label1: for i = ...)をloop先頭に書いておくと,break label1で多重ループを一気に抜けられる
break label1
- loopの先頭へ飛ぶ: continue
continue
一応、terminal用プログラムが作成できたので、ほぼおしまい。Pythonの同じプログラムと比べると、5倍程度速くなった。その後、2つプログラムを書いた。SwiftのGUI版に挑戦するのはいつになることやら。 [#ma0ccfae]
Last-modified: 2020-12-07 (月) 06:21:25