読者です 読者をやめる 読者になる 読者になる

【Swift】Appleの新言語「Swift」のリファレンスを読む(2) - Basic Operators、Strings and Characters

注意

  • あくまでメモ書きなので細かい部分を端折りますし、色々間違ってるかもしれません。ちゃんとした内容は原文を読んでね。
  • コード例は基本的に原文からそのまま引用していますが、ちょっとした注釈をつけたり、統合したりしています。
  • SyntaxHighlighterが対応してないので微妙に読みにくいです。SyntaxHighlighterはこちらのものを使用させて頂いてます。
  • 他言語にそっくりな部分でも指摘しない。(自戒)

Basic Operators(標準演算子

C Familyで使えるものはほとんど全部使える、ぐらいの認識でいいと思います。

Assignment Operator(代入演算子)、Arithmetic Operators(算術演算子)、Compound Assignment Operators(複合代入演算子:+=とか-=)、Comparison Operators(比較演算子)、Ternary Conditional Operator(三項条件演算子)の説明は割愛します。知らない単語があったら各自ぐぐってください。

Range Operators

a…bの形式で使うことが出来ます。

for index in 1...5 {
    println("\(index) times 5 is \(index * 5)")
}
// 1 times 5 is 5
// 2 times 5 is 10
// 3 times 5 is 15
// 4 times 5 is 20
// 5 times 5 is 25

bには変数をあてることも出来ます。(aは明示的に書かれていないんですが、多分いけると思います。)

また、「.」の数を一つ減らすとHalf-Closed Range Operatorになります。

let names = ["Anna", "Alex", "Brian", "Jack"]
let count = names.count
for i in 0..count {
    println("Person \(i + 1) is called \(names[i])")
}
// Person 1 is called Anna
// Person 2 is called Alex
// Person 3 is called Brian
// Person 4 is called Jack

よーく読んでみると、先ほどの1…5の例とは動作が微妙に違います。countの値は4ですが、ループの中のiの値は0〜3です。

身も蓋もない言い方をすれば「Rubyの逆」です。ここまでやるなら一緒の方がありがたいんですが。

Logical Operators

これもC Familyのアレです。

  • Logical NOT (!a)
  • Logical AND (a && b)
  • Logical OR (a || b)

そしてショートサーキットです。a && bでaがfalseならbは評価されませんし、a || bでaがtrueならbは評価されません。わざわざ割愛しなかったのはこれが言いたかっただけです。

Strings and Characters(文字列と文字)

String Literals

エスケープ文字として以下のものが紹介されています。

  • \0 (null character)
  • \ (backslash)
  • \t (horizontal tab)
  • \n (line feed)
  • \r (carriage return)
  • " (double quote)
  • ' (single quote)

また、Single-byte Unicodeは\xnn、Two-byte Unicodeは\unnnn、Four-byte Unicodeは\Unnnnnnnnで表現することが出来ます。

let wiseWords = "\"Imagination is more important than knowledge\" - Einstein"
// "Imagination is more important than knowledge" - Einstein
let dollarSign = "\x24" // $, Unicode scalar U+0024
let blackHeart = "\u2665" // ?, Unicode scalar U+2665
let sparklingHeart = "\U0001F496" // ??, Unicode scalar U+1F496

Initializing an Empty String

インスタンスの初期化方法が紹介されています。

var emptyString = "" // empty string literal
var anotherEmptyString = String() // initializer syntax
// these two strings are both empty, and are equivalent to each other

if emptyString.isEmpty {
    println("Nothing to see here")
}
// prints "Nothing to see here"

String Mutability

文字列は算術演算子で結合できる旨が書いてあります。(実際は演算子オーバーロードを使ってるんでしょうけど。)

Objective-Cとは違うよ、と言いたいみたいです。

var variableString = "Horse"
variableString += " and carriage"
// variableString is now "Horse and carriage"

let constantString = "Highlander"
constantString += " and another Highlander"
// this reports a compile-time error - a constant string cannot be modified

Strings Are Value Types

Stringは値型(value type)である、とのこと。じゃあSwiftにおける値型とはなんぞや?って話になるんですが、説明を見ようとするとClasses and StructuresのStructures and Enumerations Are Value Typesと言うセクションに飛ばされるので、詳しい話はそこですることにします。

ここで重要なのは、String(value type)を他の変数に渡しても参照を渡すわけじゃなく値をコピーして渡す、ってことでしょう。これもObjective-Cの話をしているので、まぁ、そう言うことだったんでしょう。

それと「文字列はコンパイラで最適化してるから性能面で心配する必要はないよ」とも書かれています。(原文:Swift’s compiler optimizes string usage so that actual copying takes place only when absolutely necessary.)

Working with Characters

Stringは実質Characterと言う型のCollectionです。なので、for-in構文が使えます。

for character in "Dog!??" {
    println(character)
}
// D
// o
// g
// !
// ??

明確に型を宣言することも出来ます。

let yenSign: Character = "\"

Counting Characters

文字列のカウントをする場合はcountElementsと言う組み込み関数を使って欲しいみたいです。

多分、Four-byte Unicodeとか言うたわけたものまでサポートしてしまったからでしょう。

let unusualMenagerie = "Koala ??, Snail ??, Penguin ??, Dromedary ??"
println("unusualMenagerie has \(countElements(unusualMenagerie)) characters")
// prints "unusualMenagerie has 40 characters"

Concatenating Strings and Characters

StringとCharacterは算術演算子で結合できます。複合代入演算子もOKです。

let string1 = "hello"
let string2 = " there"
let character1: Character = "!"
let character2: Character = "?"

let stringPlusCharacter = string1 + character1 // equals "hello!"
let stringPlusString = string1 + string2 // equals "hello there"
let characterPlusString = character1 + string1 // equals "!hello"
let characterPlusCharacter = character1 + character2 // equals "!?"


var instruction = "look over"
instruction += string2
// instruction now equals "look over there"

var welcome = "good morning"
welcome += character1
// welcome now equals "good morning!"

ちなみに既に値が入っているCharacterに文字(列)を足すことは出来ません。そりゃそうだとしか。

String Interpolation

Interpolationは「補完」ですね。

The Basicの章でもちらりと触れていたバックスラッシュを用いた記法を使うことで、変数や式の結果などをそのまま文字列にすることが出来ます。

let multiplier = 3
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
// message is "3 times 2.5 is 7.5"

ただし、括弧の内部にエスケープされていないダブルクォートやバックスラッシュ、改行を含めるのはダメだそうです。

Comparing Strings

文字列は比較演算子で普通に比較出来ます。

let quotation = "We're a lot alike, you and I."
let sameQuotation = "We're a lot alike, you and I."

if quotation == sameQuotation {
    println("These two strings are considered equal")
}
// prints "These two strings are considered equal"

前方一致はString#hasPrefix、後方一致はString#hasPrefixで調べることが出来ます。

let romeoAndJuliet = [
    "Act 1 Scene 1: Verona, A public place",
    "Act 1 Scene 2: Capulet's mansion",
    "Act 1 Scene 3: A room in Capulet's mansion",
    "Act 1 Scene 4: A street outside Capulet's mansion",
    "Act 1 Scene 5: The Great Hall in Capulet's mansion",
    "Act 2 Scene 1: Outside Capulet's mansion",
    "Act 2 Scene 2: Capulet's orchard",
    "Act 2 Scene 3: Outside Friar Lawrence's cell",
    "Act 2 Scene 4: A street in Verona",
    "Act 2 Scene 5: Capulet's mansion",
    "Act 2 Scene 6: Friar Lawrence's cell"
]


var act1SceneCount = 0
for scene in romeoAndJuliet {
    if scene.hasPrefix("Act 1 ") {
     ++act1SceneCount
    }
}
println("There are \(act1SceneCount) scenes in Act 1")
// prints "There are 5 scenes in Act 1"


var mansionCount = 0
var cellCount = 0
for scene in romeoAndJuliet {
    if scene.hasSuffix("Capulet's mansion") {
     ++mansionCount
    } else if scene.hasSuffix("Friar Lawrence's cell") {
     ++cellCount
    }
}
println("\(mansionCount) mansion scenes; \(cellCount) cell scenes")
// prints "6 mansion scenes; 2 cell scenes"


Uppercase and Lowercase Strings

String#uppercaseStringで全て大文字に、String#lowercaseStringで全て小文字に出来ます。

let normal = "Could you help me, please?"

let shouty = normal.uppercaseString
// shouty is equal to "COULD YOU HELP ME, PLEASE?"

let whispered = normal.lowercaseString
// whispered is equal to "could you help me, please?"

Unicode

あるStringのutf-8utf-16unicodeでの文字コード値はプロパティから簡単に取得できます。

御託を並べるよりコードを見せたほうが早そうです。こんな文字列(D, o, g, !, U+1F436)があったとします。

let dogString = "Dog!??"

それぞれこんな感じです。

// utf-8
for codeUnit in dogString.utf8 {
    print("\(codeUnit) ")
}
print("\n")
// 68 111 103 33 240 159 144 182

// utf-16
for codeUnit in dogString.utf16 {
    print("\(codeUnit) ")
}
print("\n")
// 68 111 103 33 55357 56374

// unicode
for scalar in dogString.unicodeScalars {
    print("\(scalar.value) ")
}
print("\n")
// 68 111 103 33 128054

unicodeだけvalueで取得していますね。まぁ文字コード値ですから。

scalar.valueではなくscalarをprintすると普通に文字がprintされます。

for scalar in dogString.unicodeScalars {
    println("\(scalar) ")
}
// D
// o
// g
// !
// ??