• 検索結果がありません。

Swift1.key

N/A
N/A
Protected

Academic year: 2021

シェア "Swift1.key"

Copied!
25
0
0

読み込み中.... (全文を見る)

全文

(1)

Swift

でプログラミング

してみる

2014年12月 iPhone勉強会京都

荻原剛志

京都産業大学

コマンドラインで

Swift

(2)

『詳解Swift』

対象読者としては、すでにC言語および Objective-C(あるいは少なくともJava など)によるプログラミングの経験があ る人を想定しています。   すでに出版されている入門書や雑誌記 事ではSwiftの全体像が把握できないと感 じている人には特にお勧めです。   ジェネリクスの機能や標準ライブラリ に関する解説なども含んでおり、現時点 では最も「濃い」Swift本になっていると 思います。

(3)

今日の内容

簡単なアプリケーションを作成してみよう

Swiftのプログラムの書き方について簡単な導入

プログラムの作成を通じて、Swiftの書き方に慣れる

- クラス、構造体などの定義と使い方

- C/Objective-CのAPIの呼び出し方

題材:n-gram法を使ったランダムな文書作成

日本語の文書を入力して、文字の出現頻度に関する統計情

報を得る

統計情報を利用して、ランダムな文章を作成する

(4)

主要なデータ型

種類 型名 説明 整数型 Int 整数全般に対する利用が推奨されている 整数型 UInt 符号のない整数型 実数型 Float 浮動小数点数 実数型 Double 浮動小数点数。精度が高い 論理型 Bool リテラルはtrueとfalse。整数型ではない 文字 Character Unicodeの1文字を表す。整数型ではない 文字 UnicodeScalar Unicodeの文字コードを表す 文字列 String 文字列の内容は変更可能 配列 Array<T> [T] と記述できる 辞書 Dictionary<K,V> [K:V] と記述できる オプショナル Optional<T> T? と記述できる

(5)

変数と定数

var ell : Int = 100

初期値を設定

してもよい

型を指定する。初期値

から型が分かる場合は

省略可能

let psy : Double = 0.25

いったん値を代入したら

変更できない

変数

(6)

タプル

2つ以上の値を ( ) 内に列挙したデータ型

要素数は2つ以上(あまり多い個数は勧められない)

個々の要素は別のデータ型でもよい

タプル自体を型として宣言することもできる

同じ型のタプルの間で代入が可能

var t = (10, “Ten”)

var w: (Int, String) = t

let (x, y) = t

let (_, z) = w

// x = 10, y = Ten

// z = Ten

t.0 で 10、t.1 で Ten が参照可能

_ は値を使わないことを指定

(7)

オプショナル型

var msg : String?

型の値、またはnilを

保持する

型?

msg = “

致命的エラー

msg = “”

msg = nil

var str : String

str = msg!

値を取り出す(開示: アンラップ)

値がnilの時に開示すると

実行時エラーになる

if str == nil { … }

値を開示せずに調べる

こともできる

(8)

オプショナル束縛構文

var msg : String?

if let s = msg { … }

msgがnil以外の値を持つなら、if文の条件が真になると同時に

if文の中でだけ有効な定数sにその値が代入される

let str = msg ?? “

エラー

msgがnil以外の値を持つならその値が、そうで

なければ ?? の右側の値が式の値となる

nil併合演算子

nil coalescing operator

(9)

関数の引数と返り値

func baz(n:Int, k:String) -> String

func gaz(count n:Int, name k:String)

引数はInt型で仮引数名n、String型で仮引数名kの2つ。

返り値はString型。

引数はInt型で仮引数名n、String型で仮引数名kの2つ。

返り値はなし(Void型)。

countとnameは外部引数名(キーワード)で、関数呼

び出しの時に指定しなければならない。

gaz(count:8, name:”Button”)

func kaz(_ n:Int, name k:String)

(10)

メソッドの引数

func draw(rect:CGRect, color:UIColor)

メソッド(クラス、構造体、列挙型の持つ手続き)では、第2引数

以降の仮引数名は自動的に外部引数名(キーワード)になる

draw(r, color:bgColor)

呼び出し例

- (void)drawInRect:(CGRect)rect blendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha

func drawInRect(_ rect: CGRect,

blendMode blendMode: CGBlendMode, alpha alpha: CGFloat)

Objective-C Swift これによって、Swiftの メソッド呼び出しと Objective-Cのメソッド 呼び出しの見かけが大 変良く似たものになる

(11)

関数のinout引数

func psy(inout n:Int, k:String)

inout修飾子を付けると、関数内での値の変更が呼び出し側の

変数に反映される

psy(&r, “kongloo”)

呼び出し例

引数は変数で、 & を付ける

func swap2Int(inout a:Int, inout b:Int) {

let t = a; a = b; b = t

}

スワップ関数

(12)

Cの関数を呼び出す

func fgets(_: UnsafeMutablePointer<Int8>,

_: Int32, _: UnsafeMutablePointer<FILE>)

-> UnsafeMutablePointer<Int8>

char *fgets(char *str, int size, FILE *stream);

CのAPI

Swiftから呼び出す場合のAPI

import Foundation

var buf = [Int8](count: 100, repeatedValue: 0)

while fgets(&buf, 100, stdin) != nil {

let n = strlen(buf)

if n > 0 && buf[n - 1] == 0x0a {

buf[n - 1] = 0

}

puts(buf)

}

配列の場合、値を変更しないなら & は不要

CのAPIを参照するため

0が100個格納された配列

配列の内容を変

更するため &

が必要

// 末尾の改行を削除

(13)

C関数のAPIの例

func fgets(_: UnsafeMutablePointer<Int8>,

_: Int32,

_: UnsafeMutablePointer<FILE>)

-> UnsafeMutablePointer<Int8>

func puts(_: UnsafePointer<Int8>) -> Int32

func strlen(_: UnsafePointer<Int8>) -> UInt

char *fgets(char *str, int size, FILE *stream);

Cの元のAPI

Swiftから呼び出す場合のAPI

int puts(const char *s);

(14)

作成するプログラム

統計情報

解析

生成

日本語文書

生成文字列

乱数

(15)

文字の出現頻度について

文章中の文字の出現頻度には偏りがある

直前までに現れた文字によって、次に現れる文字を

推定することができる

直前のn文字を使って、次の1文字が何かを推定する

- n文字の組み合わせを n-gram と呼ぶ

- 一般に、現在の情報だけを使って未来を推定する方法をマル

コフモデルと呼ぶ。直前のn文字から次の文字を確率的に推定

する方法(n-gram法)もこの一種である

- 文字ではなく、単語や形態素を使う方が一般的かもしれない

n-gramを使って、ランダムな文(?)を作り出す

(16)

簡単な原理

昨日も今日も寒いが、明日も寒いらしい。

3文字組では、先行する2文字が「文脈」となる

日 も

1/3 2/3

昨 日

1/1

も 寒

2/2 ★ ★ ★ ★ ★ ★ ★

も 今

1/1

今 日

1/1

寒 い

1/2 1/2

い が

1/1

(17)

データ構造

キー:文字列(String)

値:CharSet

辞書(Dictionary)

キー

昨日

日も

も今

今日

も寒

寒い

いが

CharSetクラス

entry(辞書)

 キー:文字、値:整数(Int)

total:整数(Int)

キー 値 も 1

total = 1

キー 値 今 1 寒 2

total = 3

キー 値 が 1 ら 1

total = 2

[String:CharSet]

[Character:Int]

(18)

クラス CharSet

 (1)

class CharSet {

var entry: [Character:Int]

var total = 0

init() {

entry = [:]

total = 0

}

init(_ c: Character) {

entry = [c:1]; total = 1

}

func inc(key:Character) {

if entry[key]?++ == nil {

entry[key] = 1

}

total++

}

// 続く

イニシャライザ。クラスのインスタンス を生成して初期値を与える。 辞書リテラル(空の辞書) 辞書にkeyをキーとする要素があれば カウントを1つ増やす。なければ追加。 辞書[キー] の書法で返される値は オプショナル型である 辞書 辞書リテラル(要素が1つだけ) イニシャライザは何種類か用意できる (関数のオーバーロードのように) オプショナル・チェーンと呼ばれる記法の一種。式の中で ? が付いた部分の値が nil なら、それ以上の評価をせず、 式全体の値が nil になる。

(19)

クラス CharSet

 (2)

// 続き

func randChar() -> Character {

if entry.count == 1 {

for (ch, _) in entry { return ch }

}

let rnd = Int(random() % total)

var sum = 0

for (c, v) in entry {

sum += v

if sum > rnd { return c }

}

return " " // never

}

}

乱数を使い、出現頻度に応じて、 辞書から1文字を選び出す C言語の標準ライブラリ関数 for-in文で辞書から登録内容 を1件ずつタプルとして取り 出せる 要素が1つだけなら それを取り出す for-in文で、配列や辞書、文字列などから要素を取り出 すことができる。forの後には「let」があると考えれば よく、識別子はループ内で有効な定数となる。

(20)

関数 readfile

func readfile(path:String) -> NSString? { var err: NSError? = nil

var cont = NSString(contentsOfFile:path, encoding:NSUTF8StringEncoding, error: &err) // ポインタの渡し方に注意! if cont == nil { println( err?.localizedDescription ?? "ファイルが読めません") } return cont }

convenience init?(contentsOfFile path: String, encoding enc: UInt,

error error: NSErrorPointer) - (instancetype)initWithContentsOfFile:(NSString *)path encoding:(NSStringEncoding)enc error:(NSError **)error

Objective-C

Swift

ファイルの内容を読み込 んで文字列として返す

(21)

クラス RandomChat

 (1)

var maxlen: Int = 3 class RandomChat {

var dic: [String:CharSet] = [:] var startChars : CharSet

init() {

startChars = CharSet() }

// 続く

func makeModel(str: String) { var chseq = [String]()

var pttn = "" for ch in str { if ch <= Character(" ") { continue } if pttn == "" { if ch == Character(" ") { continue } startChars.inc(ch) }else {

if let cset = dic[pttn] { cset.inc(ch) }else { dic[pttn] = CharSet(ch) } } if ch == "。" || ch == "." { pttn = ""; chseq = [] }else { chseq.append(String(ch)) if chseq.count >= maxlen { chseq.removeAtIndex(0) } pttn = join("", chseq) } } } // 続く 全角空白 空のCharSetを作る

dic: 「文脈」文字列をキーと

してCharSetを持つ辞書

startChars: 文の先頭に現れ

る文字を、出現頻度とと

もに持つ辞書

文脈を構成する 文字を含む配列 文脈を構成する文字列 // 文字を接続 決まった 長さを超 えたら先 頭を削除 文末 文脈に文字 を追加 文頭 文脈が辞書にあれば文字のカウン タを増やす。なければ辞書に追加。 クラス変数 の代わり

(22)

クラス RandomChat

 (2)

// 続き

func makeStatment() -> String {

var pttn = String(startChars.randChar()) var chseq = [pttn]

var strbuf = pttn

while let cset = dic[pttn] { let ch = cset.randChar() let s = String(ch) strbuf += s if s == "。" || s == "." { break } chseq.append(s) if chseq.count >= maxlen { chseq.removeAtIndex(0) } pttn = join("", chseq) } return strbuf } } 文脈に対応するCharSet 文脈を構成する文字を含む配列 文脈を構成 する文字列 // 文字を接続 文頭となる 文字を選ぶ 文末 作った文字列を 格納しておく 文脈の後に続く文字を 適当に1つ選ぶ 文脈に文字 を追加 決まった長さを超えたら先頭を削除

(23)

コマンドライン引数

var C_ARGC: CInt

var C_ARGV: UnsafeMutablePointer<UnsafeMutablePointer<Int8>>

$ swift comm.swift -help "(^ ^;" 0: "comm.swift"

1: "-help" 2: "(^ ^;"

$ swiftc comm.swift

$ ./comm -magic=10 -flag=NO 100 0: "./comm" 1: "-magic=10" 2: "-flag=NO" 3: "100"

実行例

実行例

for var i = 0; i < Int(C_ARGC); i++ {

if let s = String.fromCString(C_ARGV[i]) {

println("\(i): \"\(s)\"")

}

}

(24)

実行

̶1つのファイルにまとめて

class CharSet

class RandomChat

srandom(UInt32(time(nil))) maxlen = 5

var chat = RandomChat()

for var i = 1; i < Int(C_ARGC); i++ {

if let s = String.fromCString(C_ARGV[i]) { if let text = readFile(s) {

chat.makeModel(text) } } } for _ in 0 ..< 10 { println(chat.makeStatment()) }

chats.swift

$ swift chats.swift ファイル… または $ swiftc chats.swift $ ./chats ファイル… Swiftではクラスや関数の宣言順序を 意識する必要がない。 func readFile

(25)

実行

̶個別のファイルをコンパイル

class CharSet

class RandomChat func readFile

main

$ swiftc -o chats main.swift CharSet.swift RandomChat.swift $ ./chats ファイル… Swiftではそれぞれのクラスファイルを別々にコンパイル しておくのではなく、まとめてコンパイルするのが標準 的な方法

main.swift

RandomChat.swift

CharSet.swift

参照

関連したドキュメント

(注)本報告書に掲載している数値は端数を四捨五入しているため、表中の数値の合計が表に示されている合計

、肩 かた 深 ふかさ を掛け合わせて、ある定数で 割り、積石数を算出する近似計算法が 使われるようになりました。この定数は船

(火力発電のCO 2 排出係数) - 調整後CO 2 排出係数 0.573 全電源のCO 2 排出係数

(火力発電のCO 2 排出係数) - 調整後CO 2 排出係数 0.521 全電源のCO 2 排出係数

前掲 11‑1 表に候補者への言及行数の全言及行数に対する割合 ( 1 0 0 分 率)が掲載されている。

(注)本報告書に掲載している数値は端数を四捨五入しているため、表中の数値の合計が表に示されている合計

その太陽黒点の数が 2008 年〜 2009 年にかけて観察されな

高齢者 に優 しい交通環境 を整備す るため、バ リアフ リー対応型信号機 の整備、道 路標識 ・標示 の高輝度化等の整備