詳解Swift(5)〜基本的なデータ型

2016. 06. 28
(※2016年6月28日追記:この記事は詳解 Swift(初版第1刷)を元に、Xcode 7.3.1(Swift 2.2)下における加筆・修正を行っています。(Xcode 7.3からXcode 7.3.1での変更点はありません))



CHAPTER 05 基本的なデータ型



●5.1 整数と実数


・範囲型と区間型

範囲型のイニシャライザ init(start:end:) ですが「'init(start:end:)' は Swift 3 で削除するため廃止になりました。 '..<' 演算子を使用するように」と警告が出るようになりました。

8042.png

本書(Swift 1.1ベース)ではswitch文の条件に使える構造体は区間型のみで、範囲型を使うとエラーになるとありますが、Xcode 6.4(Swift 1.2)以降では範囲型も扱えるようです。

var rg = Range<Int>(0..<10)

let n = 5
switch n {
case rg: print("Range")        // Range(エラーなし)
default: break
}

Xcode Release Notes」などを検索しても、いつ改訂されたか分からなかったのですが、「The Swift Programming Language (Swift 2.1)(Language Guide/Control Flow/Conditional Statements/Switch)」に範囲演算子は区間型か範囲型を返すようにオーバーロードされるとの記述がありました。

「注
閉範囲演算子(...)と半開範囲演算子(..<)関数は共に、区間型または範囲型のいずれかを返すようにオーバーロードされます。
たとえばswitch文のcaseで照合する時など、特定の要素が含まれているかどうかを判断することができます。
範囲はfor-in文で反復処理される連続した値のコレクションです。」


ただしfor-in文は範囲型のみ使用可なのは変わらず、(半開区間・閉区間問わず)区間型はエラーになります。

var inth = HalfOpenInterval<Int>(0, 10)
for i in inth { print(i) }        // 'error: type 'HalfOpenInterval<Int>' does not conform to protocol 'SequenceType'


・Stride型

従来のstrideメソッドはエラーが出るようになりました。

var st1 = stride(from: 8, through: 20, by: 4)        // error: 'stride(from:through:by:)' is unavailable: call the 'stride(through:by:)' method instead
for i in st1 { print(" (i)", terminator: "") }
print()
var st2 = stride(from: 8, to: 20, by: 4)        // error: 'stride(from:to:by:)' is unavailable: call the 'stride(to:by:)' method instead
for i in st2 { print(" (i)", terminator: "") }
print()

こちらも「Xcode Release Notes」などを検索しても、いつ改訂されたか分からなかったのですが、「InfoQ/Swiftに対するIBMの反応」によるとグローバルメソッドからメンバーメソッドに置き換えられたようです。
したがって上記の例は以下のように修正することになります。

var st1 = 8.stride(through: 20, by: 4)
for i in st1 { print(" (i)", terminator: "") }        // 8 12 16 20
print("")
var st2 = 8.stride(to: 20, by: 4)
for i in st2 { print(" (i)", terminator: "") }        // 8 12 16
print("")

なお実数型に適用したst4の例で出力結果が「0.0, 0.1, ... 0.8」となっていますが、「0.0, 0.2, ... 0.8」の誤りです。



●5.2 文字列と文字


・String型のメソッド

compareメソッドの戻り値がInt型とありますが、現在はNSComparisonResultが返ってきます。

let str: String = "三"
let cmp: Int = str.compare("四")        // error: cannot convert value of type 'NSComparisonResult' to specified type 'Int'

ただ、このcompareメソッドに関しては「Swift Standard Library Reference/String Structure Reference」や「The Swift Programming Language (Swift 2.1)/Strings and Characters」では見当たらず、「Xcode 7 Release Notes」でも削除や変更について言及されていないのでよく分からない状態です。

The Swift Programming Language (Swift 2.1)/Strings and Characters」でも等価性の比較には == を使っているので、文字列の比較は等号・不等号を使用するようになったのかもしれません。

str == "三"        // true
str > "四"        // false

また toInt() メソッドは「詳解Swift(4)〜オプショナル」で述べたように Int(String) イニシャライザに改名されています。


・文字列の長さとNSStringへの変換

文字列の長さ(文字数)を数えるために使用している関数 countElements() はSwift 1.2で廃止されてcount() を使用するようになりました(「Qiita/仕様変更【 Swift1.2 / Xcode6.3】まとめ」「Dorapro エンジニアBLOG/[Swift] Xcode6.3に上げたらビルドが通らなかった話」参照)が、Swift 2で .characters.count に再変更されたようです(「Qiita/Swiftで文字列長」「Swift 2における文字列」参照)。

現在の文字数の数え方については「The Swift Programming Language (Swift 2.1)/Strings and Characters(Counting Characters)」で以下のように詳細が綴られています。

文字の数え方

文字列内のCharacter値の数を取得するには、文字列のcharactersプロパティのcountプロパティを使用します。

let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪"
print("unusualMenagerie has (unusualMenagerie.characters.count) characters")
// prints "unusualMenagerie has 40 characters"

SwiftのCharacter値では拡張書記素クラスタの使用は文字列の連結を意味し、変更が常に文字列の文字数に影響を与えるとは限らないことに注意してください。

例えば4文字からなる単語 cafe で新たに文字列を初期化した際、その後文字列の最後に COMBINING ACUTE ACCENT(U+0301)を追加すると、結果の文字列は文字数は4文字のままで4番目の文字は e ではなくé になります。

var word = "cafe"
print("the number of characters in (word) is (word.characters.count)")
// prints "the number of characters in cafe is 4"

word += "u{301}"        // COMBINING ACUTE ACCENT, U+0301

print("the number of characters in (word) is (word.characters.count)")
// prints "the number of characters in café is 4"




拡張書記素クラスタは1つ以上のUnicodeスカラで構成することができます。
これは異なる文字(や同じ文字で異なる表現)を格納するために必要なメモリ量が異なることを意味します。
このためSwiftの文字は、文字列表現におけるメモリの各消費量が同じではありません。
したがって文字列の文字数は、拡張書記素クラスタ境界を決定するため文字列を反復処理しなければ算出することはできません。
特に長い文字列値を処理する場合、charactersプロパティは文字列の文字を決定するため、文字列全体のUnicodeスカラを反復処理する必要があることに注意してください。

charactersプロパティによって返される文字数は、同じ文字を含むNSStringのlengthプロパティと常に同じではありません。
NSStringでの長さは、文字列のUTF-16表現における16ビットコード単位での数に基づいており、文字列内のUnicode拡張書記素クラスタの数ではありません。


したがって最初の例は以下のように修正することになります。

var a = "Life is short and time is swift."
countElements(a)        // error: use of unresolved identifier 'countElements'
count(a)        // error: cannot invoke 'count' with an argument list of type '(String)'
a.characters.count        // 32

その次のNSStringとString間の変換機能は、FoundationやCocoaだけでなくUIKitをインポートしていれば使用できます。

また utf16Count も「Xcode Release Notes(Xcode 6.3 Release Notes/Changes, Enhancements, and Notes/Swift Standard Library Enhancements and Changes)」にてSwift 1.2で削除されたとありましたが、

「utf16CountはStringから削除されました。代わりにStringのUTF16ビュー上でcountを使用してください。(17627758)」

Swift 2ではUTF-16ビューでのカウントは .utf16.count を代わりに使用するようにと促されます。

a.utf16Count        // error: 'utf16Count' is unavailable: Take the count of a UTF-16 view instead, i.e. str.utf16.count
count(a.utf16)        // error: 'count' is unavailable: access the 'count' property on the collection
a.utf16.count        // 32


・合成された文字の問題

ここでもutf16CountとcountElementsが使用されていますが、上記の通り使用不可なのでそれぞれ.utf16.countと.characters.countに修正することになります。

print( str.utf16Count )        // error: 'utf16Count' is unavailable: Take the count of a UTF-16 view instead, i.e. str.utf16.count
print( str.utf16.count )
print( countElements(str) )        // error: use of unresolved identifier 'countElements'
print( str.characters.count )

また「詳解Swift(1)〜Swiftでプログラミング」の「for-in文」の項で述べたように、String型がSequenceTypeプロトコルに準拠しなくなったので、文字列からfor-in文で文字を取り出すには characters プロパティを使用する必要があります。

for cc in str { print("(cc):", terminator: "") } ; print()        // error: type 'String' does not conform to protocol 'SequenceType'
for cc in str.characters { print("(cc):", terminator: "") } ; print()



●5.3 配列


・部分配列

変数・定数の型はdynamicTypeで調べることができます。
(「Qiita/Swiftで自分のクラス名を表示する方法」参照)

var conso = ["K", "S", "T", "N", "H", "M", "Y", "R", "W"]
let sub = conso[3...5]
print(sub)
conso.dynamicType        // Array<String>.Type
sub.dynamicType        // ArraySlice<String>.Type

let subarray = [String](sub)
subarray.dynamicType        // Array<String>.Type


・配列のイニシャライザ

上記の通りStride型メソッドの書式が変わりましたので、定数 arr2 は次のように定義することになります。

let arr2 = [Double](stride(from: 20.0, through:0.0, by:-0.5))        // error: 'stride(from:through:by:)' is unavailable: call the 'stride(through:by:)' method instead

let arr2 = [Double](20.0.stride(through:0.0, by:-0.5))


・配列のメソッド

配列を逆順にする reverse メソッドを単純に実行しようとすると上手くいきません。

let test = ["壱", "弐", "参"]
let rev = test.reverse()    // ReverseRandomAccessCollection<Array<String>>
print("\(rev), \(test)")    // "ReverseRandomAccessCollection<Array<String>>(_base: ["壱", "弐", "参"]), ["壱", "弐", "参"]\n"

これは「Qiita/ReverseRandomAccessCollectionの挙動」によると、新たに作成される逆順配列がインデックスされていないためのようです。
この記事では print 文中でイニシャライズして対処しています。

let rev = test.reverse()    // ReverseRandomAccessCollection<Array<String>>
print("\(Array(rev)), \(test)")    // "["参", "弐", "壱"], ["壱", "弐", "参"]\n"

ただ reverse メソッド実行時(逆順配列生成時)に問題が解決されていないのは少々気持ち悪いものです。
そこで思いつきで受け入れる定数 rev を型宣言してみたところ上手くいきました。

let rev: [String] = test.reverse()    // ["参", "弐", "壱"]
print("\(rev), \(test)")    // "["参", "弐", "壱"], ["壱", "弐", "参"]\n"

また配列の sort メソッドを実行しても並べ替えらず結果が変わりません。

var p = ["Mercury", "Venus", "Jupiter"]
p.sort( { $0 < $1 } )
print(p)        // ["Mercury", "Venus", "Jupiter"]

これは「モバイル開発系(K)/iOS Objective-C, Swift Tips/配列をソートする(Swift) [Array, sort, sortInPlace]」で指摘されているように、Swift 2.0 でメソッド名が変更されているためです。

これに関しては「Xcode Release Notes(Xcode 7.0 Release Notes/Swift/Swift Standard Library)」で次のように記述されています。

「find は indexOf() に改名し、sortは sortInPlace()に改名、そして sorted() は sort() に改名しました。」

つまり上記の p.sort() は Swift 1.2 以前における p.sorted() が実行されたことになり、配列 p の要素が変更されなかったわけです。
実際 p.sort() の結果を別の配列 q に代入すると、q は並べ替えられた要素を持つ配列になります。

let q = p.sort( { $0 < $1 } )
print(p)        // ["Mercury", "Venus", "Jupiter"]
print(q)        // ["Jupiter", "Mercury", "Venus"]

したがって配列 p 自身の要素を並べ替えるには sortInPlace() を使用します。

p.sortInPlace( { $0 < $1 } )
print(p)        // ["Jupiter", "Mercury", "Venus"]


・配列とfor-in文

関数 findString の定義でエラーが出ますが、これは「詳解Swift(2)〜関数(2.1 関数定義の基本/外部引数名)」で述べたように、関数の内部引数名と外部引数名を同じにするための # は使用できなくなったためで、第1引数の外部引数名は明示する必要があります。

func findString(#key:String, words:[String]) -> Bool {        // '#' has been removed from Swift; double up 'key key' to make the argument label the same as the parameter name

func findString(key key:String, words:[String]) -> Bool {

また Swift 2.0 で reverse 関数が廃止されたようで(「tmp/Swift1.2 -> Swift2」参照)エラーが出るようになり、代わりにメソッドの reverse() を使用するよう促されます。

for v in reverse(arr) { print("\(v) ", terminator: "") }        // error: 'reverse' is unavailable: call the 'reverse()' method on the collection


・可変個の引数が利用できる関数

本項の主旨から逸れますが「詳解Swift(1)〜Swiftでプログラミング(1.2 制御構文/print文)」で述べたように、Swift 2.0 からprintln 関数が廃止されると同時に print 関数が可変長引数を持てるなど改善がなされました。
(「Swift Standard Library Reference/Swift Standard Library Functions Reference/print(_:separator:terminator:)」参照)
したがって現在は print 文単体で可変長引数を処理することができます。

print("Output:", 3, 1, 4, 6, 7)        // Output: 3 1 4 6 7



Wikipedia/NaN

Qiita/Swift - 範囲変数を使った case の書き方

Qiita/Swift での Int 型 switch case の落とし穴(?)

InfoQ/Swiftに対するIBMの反応

Swift Standard Library Reference/String Structure Reference

Xcode 7 Release Notes

The Swift Programming Language (Swift 2.1)/Strings and Characters

Qiita/仕様変更【 Swift1.2 / Xcode6.3】まとめ

Dorapro エンジニアBLOG/[Swift] Xcode6.3に上げたらビルドが通らなかった話

Qiita/Swiftで文字列長

Qiita/Swiftで自分のクラス名を表示する方法

モバイル開発系(K)/iOS Objective-C, Swift Tips/配列をソートする(Swift) [Array, sort, sortInPlace]

tmp/Swift1.2 -> Swift2

Swift Standard Library Reference/Swift Standard Library Functions Reference/print(_:separator:terminator:)

Qiita/ReverseRandomAccessCollectionの挙動

詳解 Swift 改訂版(Amazon)
 






QuietControl 30 wireless headphones
0 Comments
Leave a comment
管理者にだけ表示を許可する
Top
0 Trackbacks
Top
Calendar
10 | 2017/11 | 12
Sun Mon Tue Wed Thu Fri Sat
- - - 1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 - -
Recent Articles
iTunes


Swift
Categories
Tips
Profile

水月杏香

Author:水月杏香
永遠の初心者プログラマ。

Wish List
WACOM


ARC
Technical Q&A
情報プロパティリストキー
Start Developing iOS Apps Today
BOSE

QuietControl 30 wireless headphones
Reference
NSApplicationDelegateプロトコル
NSArrayクラス
NSAutoreleasePoolクラス
NSBundleクラス
NSBundle UIKit追加分
NSCalendarクラス
NSCoderクラス
NSCodingプロトコル
NSCopyingプロトコル
NSDataクラス
NSDateクラス
NSDateFormatterクラス
NSDictionaryクラス
NSEntityDescriptionクラス
NSEnumeratorクラス
NSErrorクラス
NSExceptionクラス
NSFetchRequestクラス
NSFileHandleクラス
NSFileManagerクラス
NSIndexPathクラス
NSIndexPath UIKit追加分
NSKeyedArchiverクラス
NSKeyedUnarchiverクラス
NSKeyValueCodingプロトコル
NSLocaleクラス
NSManagedObjectクラス
NSManagedObjectContextクラス
NSManagedObjectModelクラス
NSMutableArrayクラス
NSMutableCopyingプロトコル
NSMutableDictionaryクラス
NSMutableSetクラス
NSNotificationクラス
NSNotificationCenterクラス
NSNullクラス
NSNumberクラス
NSObjectクラス
NSObject UIKit追加分
NSObjectプロトコル
NSPersistentStoreクラス
NSPersistentStoreCoordinatorクラス
NSPredicateクラス
NSPropertyListSerializationクラス
NSRunLoopクラス
NSSetクラス
NSStringクラス
NSString UIKit追加分
NSTimerクラス
NSTimeZoneクラス
NSURLクラス
NSURLProtectionSpaceクラス
NSURLRequestクラス
NSUserDefaultsクラス
NSValueクラス

UIActionSheetクラス
UIActionSheetDelegateプロトコル
UIActivityIndicatorViewクラス
UIAlertViewクラス
UIAlertViewDelegateプロトコル
UIApplicationクラス
UIApplicationDelegateプロトコル
UIBarButtonItemクラス
UIBarItemクラス
UIButtonクラス
UIColorクラス
UIControlクラス
UIDatePickerクラス
UIDeviceクラス
UIEventクラス
UIFontクラス
UIGestureRecognizerクラス
UIImageクラス
UIImageViewクラス
UIKit Function
UILabelクラス
UINavigationControllerクラス
UINavigationItemクラス
UIPickerViewクラス
UIPickerViewDataSourceプロトコル
UIPickerViewDelegateプロトコル
UIPinchGestureRecognizerクラス
UIResponderクラス
UIScreenクラス
UIScrollViewクラス
UISearchBarクラス
UISearchBarDelegateプロトコル
UISegmentedControlクラス
UISliderクラス
UISwipeGestureRecognizerクラス
UISwitchクラス
UITableViewクラス
UITableViewCellクラス
UITableViewControllerクラス
UITableViewDataSourceプロトコル
UITableViewDelegateプロトコル
UITapGestureRecognizerクラス
UITextFieldクラス
UITextFieldDelegateプロトコル
UITextInputTraitsプロトコル
UITextViewクラス
UITextViewDelegateプロトコル
UIToolbarクラス
UITouchクラス
UIViewクラス
UIViewControllerクラス
UIWebViewクラス
UIWebViewDelegateプロトコル
UIWindowクラス

AVAudioPlayerクラス
AVAudioPlayerDelegateプロトコル

CADisplayLinkクラス
CAEAGLLayerクラス
CALayerクラス

CGAffineTransform
CGBitmapContext
CGColor
CGColorSpace
CGContext
CGGeometry
CGImage
CGPath

EAGLContextクラス
EAGLDrawableプロトコル

Foundation Constants
Foundation Data Types
Foundation Functions

MPMediaItemクラス
MPMediaItemArtworkクラス
MPMediaPlaylistクラス
MPMediaPropertyPredicateクラス
MPMediaQueryクラス
MPMusicPlayerControllerクラス

Randomization Services

System Sound Services
Amazon


OpenGL ES
SQLite
Monthly Archives
Recent Comments
Recent TrackBacks
RSS Link
Visitors
QR Code
QR