詳解Swift改訂版(05)〜基本的なデータ型

2017. 01. 13
この記事は詳解 Swift 改訂版(初版第1刷)を元に、Xcode 8.2.1(Swift 3.0.2)下における差異を記述しています。



CHAPTER 05 基本的なデータ型



●5.1 整数と実数


・範囲型と区間型

Qiita/Swift 3.0のRangeまとめ」や「Qiita/Swift 3のRange徹底解説」で述べられているように、Swift 3 で範囲型と区間型の仕様が変わりました。

Swift 2.2 での区間型 HalfOpenInterval<T> と ClosedInterval<T> は Swift 3.0 では Range<T> と ClosedRange<T> になり、これまで閉区間のなかった(閉区間を指定できるが実際には半開区間だった)範囲型 Range<T> は CountableRange<T> と CountableClosedRange<T> に分けられました。
(特に Range<T> が範囲型から区間型に変更されたことに注意が必要です。)

範囲型区間型
半開区間閉区間半開区間閉区間
Swift 2.2Range<T>-HalfOpenInterval<T>ClosedInterval<T>
Swift 3.0Countable
Range<T>
Countable
ClosedRange<T>
Range<T>ClosedRange<T>
整数Int
UInt
実数Double
Float
××
文字
文字列
Character
String
××
BoundComparable
Strideable××
Bound.StrideSignedInteger××
RandomAccessCollection××
for-in 文での利用××
switch 文での利用

したがって型宣言をした範囲演算子による初期化は以下のようになります。

var inth: HalfOpenInterval<Int> = 0..<10        // error: 'HalfOpenInterval' has been renamed to 'Range'
var inth: Range<Int> = 0..<10

var intc: ClosedInterval<Int> = 0...10        // error: 'ClosedInterval' has been renamed to 'ClosedRange'
var inc: ClosedRange<Int> = 0...10

var rg: Range<Int> = 0..<10        // 範囲型ではなく半開区間型になる
var rgh: CountableRange<Int> = 0..<10

var rgc: CountableClosedRange<Int> = 0...10

イニシャライザを使った初期化は以下のようになります。

var inth = Range<Int>(uncheckedBounds: (0, 10))
var intc = ClosedRange<Int>(uncheckedBounds: (0, 10))
var rgh = CountableRange<Int>(uncheckedBounds: (0, 10))
var rgc = CountableClosedRange<Int>(uncheckedBounds: (0, 10))

パターンマッチ演算子の例において、型を指定せず範囲演算子に文字列(または文字や実数)を指定した場合は区間型に、整数を指定した場合は範囲型になります。

var sintv = "archer" ... "saber"        // ClosedRange("archer"..."saber")

var rg = -5 ... 5        // CountableClosedRange(-5...5)

let intv = 0.0 ..< 8.0        // Range(0.0..<8.0)



●5.2 配列


・配列とプロトコル

配列の要素を逆順に並べ換える reverse() メソッドはエラーが出るようになりました。

for item in s.reverse() { print(item) }        // error: 'reverse()' has been renamed to 'reversed()'

Study Swift/Reverse Array in Swift 2.2/3.0」によると、Swift 3 から reversed() に改名されたようです。

for item in s.reversed() { print(item) }        // 冬 秋 夏 春


・配列のイニシャライザ

イニシャライザ init(count:Int, repeatedValue:T) はエラーが出るようになりました。

var data = [Double](count:10, repeatedValue:0.0)        // error: argument 'repeatedValue' must precede argument 'count'

articles of samekard/Swift2.2からSwift3.0への変換を行ってみて」によると、Swift 3 から init(repeating:T, count:Int) に変更されたようです。

var data = [Double](repeating:0.0, count:10)        // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]


・配列のメソッド

メソッド insert(_: T, atIndex: Int) はエラーが出るようになりました。

s.insert("零", atIndex:0)        // error: incorrect argument label in call (have '_:atIndex:', expected '_:at:')

Swift 3 から insert(_: T, at: Int) に変更されたようです。

s.insert("零", at: 0)        // ["零", "壱", "弐", "参"]

また removeAtIndex(_: Int) -> T もエラーが出るようになりました。

let one = s.removeAtIndex(1)        // error: 'removeAtIndex' has been renamed to 'remove(at:)'

Swift 3 から remove(at: Int) -> T に改名されたようです。

let one = s.remove(at: 1)        // "壱"



●5.3 文字列と文字


・String型のイニシャライザ

String 型のイニシャライザで配列を渡すとエラーが出るようになりました。

let b = String([6001, 5210])        // error: 'init' has been renamed to 'init(describing:)'

Developers.IO/[Swift 3] 型名を取得する」によると、init(describing:) が Swift 3 で追加されたようです。

let b = String(describing: [6001, 5210])        // "[6001, 5210]"

また同じ値を複数回繰り返すイニシャライザ init(count:repeatedValue:) は init(repeating:count:) に改名され、Character 型および UnicodeScalar 型は指定できなくなり、String 型のみになりました。
(String 型を繰り返す init(count:repeatedValue:) は元々無かった?)

// init(count:repeatedValue:)

let char: Character = "花"
let sc = String(count: 10, repeatedValue: char)        // error: 'init(count:repeatedValue:)' is unavailable: Renamed to init(repeating:count:) and reordered parameters

let str: String = "華"
let ss = String(count: 10, repeatedValue: str)        // error: cannot invoke initializer for type 'String' with an argument list of type '(count: Int, repeatedValue: String)'

let us = (UnicodeScalar(0x83ef))!
let su = String(count: 10, repeatedValue: us)        // error: 'init(count:repeatedValue:)' is unavailable: Renamed to init(repeating:count:) and reordered parameters


// init(repeating:count:)

let sc = String(repeating: char, count: 10)        // error: 'init(repeating:count:)' is unavailable: Replaced by init(repeating: String, count: Int)

let ss = String(repeating: str, count: 10)        // "華華華華華華華華華華"

let su = String(repeating: us, count: 10)        // error: 'init(repeating:count:)' is unavailable: Replaced by init(repeating: String, count: Int)


・UnicodeScalar 型

Int 型と String 型を引数とした UnicodeScalar 型定数の比較でエラーが出るようになりました。

let us1 = UnicodeScalar(0x83ef)        // Int 型引数
let us2 = UnicodeScalar("澪")        // String 型引数
let us3 : UnicodeScalar = "箒"        // unicodeScalarLiteral

us1 > us2        // error: binary operator '>' cannot be applied to two 'UnicodeScalar?' operands

これは「Apple Developer Documentation/Swift Standard Library/UnicodeScalar」で説明されているように、Int 型や String 型を引数としたイニシャライザの返り値はオプショナル型であり、また「詳解Swift改訂版(04)〜オプショナル」で述べたように比較演算子がオプショナル型の値を受け付けなくなったためです。
したがって比較するには開示する必要があります。

type(of: us1)        // Optional<UnicodeScalar>.Type
type(of: us2)        // Optional<UnicodeScalar>.Type
type(of: us3)        // UnicodeScalar.Type

us1! > us2!        // true

List5-3 においても、定数 first と last は Int 型を引数としたイニシャライザのためオプショナル型になるので、プロパティ unicodeScalars の値と比較するには開示する必要があります。

let first = UnicodeScalar(0x3041)        // Optional<UnicodeScalar>.Type
let last = UnicodeScalar(0x309f)        // Optional<UnicodeScalar>.Type

for sc in text.unicodeScalars {        // String.UnicodeScalarView.Type
    if sc >= first && sc <= last {        // error: binary operator '>=' cannot be applied to operands of type 'String.UnicodeScalarView.Iterator.Element' (aka 'UnicodeScalar') and 'UnicodeScalar?'


let first = UnicodeScalar(0x3041)!        // UnicodeScalar.Type
let last = UnicodeScalar(0x309f)!        // UnicodeScalar.Type

また String 型のインスタンスメソッド append() の引数は String 型もしくは Character 型 のみに対応しているので、UnicodeScalar 値を使うにはイニシャライザを使う必要があります。
(「Apple Developer Documentation/Swift Standard Library/String」参照)

kana.append(sc)        // error: 'append' is unavailable: Replaced by append(_: String)

kana.append(String(sc))


・指定位置の文字および部分文字列の取り出し方

本文では使用していませんが、指定範囲の文字列を取得する subscript は範囲型(の旧 Range<String.Index> )ではなく区間型になり、半開区間が subscript(Range<String.Index>)、閉区間が subscript(ClosedRange<String.Index>) となっています。

文字列中の任意の文字、部分文字列を参照する例ですが、プロパティ startIndex や endIndex で示しているインデックス位置を前後させるメソッド successor() と predecessor() は廃止され、代わりに index(after: String.Index) と index(before: String.Index) を使用することになりました。

また指定した値分を移動させる advance() も廃止されて代わりに index(String.Index, offsetBy: String.IndexDistance) か index(String.Index, offsetBy: String.IndexDistance, limitedBy: String.Index) を使用することになっています。
(「大津真 Web/Swift 3 文字列操作(その2)」参照)

print( str[str.startIndex.successor()] )        // error: 'successor()' is unavailable: To get the next index call 'index(after:)' on the CharacterView instance that produced the index.
print( str[advance(str.startIndex, 9)] )        // error: use of unresolved identifier 'advance'

print( str[str.endIndex.predecessor()] )        // error: 'predecessor()' is unavailable: To get the previous index call 'index(before:)' on the CharacterView instance that produced the index.
print( str[advance(str.endIndex, -3)] )        // error: use of unresolved identifier 'advance'

let x = advance(str.startIndex, 7)        // error: use of unresolved identifier 'advance'
let y = advance(x, 5)        // error: use of unresolved identifier 'advance'

簡略化のため startIndex と endIndex を定数に入れ、メソッドを修正すると以下のようになります。

let sIndex = str.startIndex        // 0
let eIndex = str.endIndex        // 19

print( str[sIndex] )        // 俺
print( str[str.index(after: sIndex)] )        // 、
print( str[str.index(sIndex, offsetBy: 9)] )        // グ

print( str[str.index(before: eIndex)] )        // 。
print( str[str.index(eIndex, offsetBy: -3)] )        // ま

let x = str.index(sIndex, offsetBy: 7)        // 7
let y = str.index(x, offsetBy: 5)        // 13

List5-5 において、String.Index 型の変数 x1 と x2 はインクリメント演算子が使えないだけでなく、Int 値との演算もできません。

x1 += 1; x2 += 1        // error: binary operator '+=' cannot be applied to operands of type 'String.Index' (aka 'String.CharacterView.Index') and 'Int'

したがってインデックス位置を進めるメソッド index(after:) を使用する必要があります。

x1 = s1.index(after: x1); x2 = s2.index(after: x2)

なお subscript で単純な整数を使えない理由に関しては「Medium/Swift・iOSコラム/Swift 3のStringのCharacter Viewを、なぜIntでsubscript出来ないのか分からない」と「Medium/Swift・iOSコラム/Swift 3のStringのViewに対して、Intでsubscript出来ない理由」を参照すると良いでしょう。


・String 型のメソッド

メソッド append() について、上述の通り現在は append(String) と append(Character) は使えますが UnicodeScalar 型を引数にすることはできませんので注意してください。

let a: Character = "a"
let b: String = "bbb"
var c: String = "ccc"

c.append(a)        // ccca
c.append(b)        // cccabbb

let d: UnicodeScalar = "d"

c.append(d)        // error: 'append' is unavailable: Replaced by append(_: String)

メソッド appendContentsOf() は append(contentsOf:) に、insert(_:atIndex:) は insert(_:at:) に、insertContentsOf(_:at:) は insert(contentsOf:at:) に改名されています。

let e: [Character] = ["e", "E"]        // Character 型を要素とする CollectionType 型

// append(contentsOf:)

c.appendContentsOf(e)        // error: 'appendContentsOf' has been renamed to 'append(contentsOf:)'
c.append(contentsOf: e)        // cccabbbeE

let sIndex = c.startIndex
let eIndex = c.endIndex

// insert(_:at:)

c.insert("f", atIndex: c.index(sIndex, offsetBy: 8))        // error: incorrect argument label in call (have '_:atIndex:', expected '_:at:')
c.insert("f", at: c.index(sIndex, offsetBy: 8))        // cccabbbefE

// insert(contentsOf:at:)

c.insertContentsOf(e, at: eIndex)        // error: 'insertContentsOf(_:at:)' has been renamed to 'insert(contentsOf:at:)'
c.insert(contentsOf: e, at: eIndex)        // cccfabbbefeEE
// 直前の insert(_:at:) で eIndex の示す位置が "E の次" ではなく "E" になるため cccabbbefEeE とはならない

メソッド removeAtIndex() は remove(at:) に改名されています。

c.removeAtIndex(sIndex)        // error: 'removeAtIndex' has been renamed to 'remove(at:)'
c.remove(at: sIndex)        // c

余談ですが remove(at:) で試しに endIndex の定数を指定したところ(そのインデックスに値が存在しているのに)エラーになりました。

c.remove(at: eIndex)        // error:Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode= 0x0).

不思議に思い前後関係を調べると、endIndex と index(after:) で求めたその次のインデックスが同じという結果でした。

c.index(before: eIndex)        // 8
eIndex        // 9
c.index(after: eIndex)        // 9

理由は分かりませんが subscript でも endIndex を指定するとエラーになり、当該インデックスを指定するには index(after:) で指定しなければならないようなので注意が必要です。

print(c)        // ccabbbefeEE

print(c[c.index(before: eIndex)])        // e
print(c[eIndex])        // error:Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode= 0x0).
print(c[c.index(after: eIndex)])        // E

メソッド removeRange() は半開区間の removeSubrange(Range<String.Index>) と閉区間の removeSubrange(ClosedRange<String.Index>) に改名されました。

let x = c.index(sIndex, offsetBy: 1)        // 1
let y = c.index(x, offsetBy: 2)        // 3
let xy1 = x ..< y        // 1..<3
let xy2 = x ... y        // 1...3

print(c)        // ccabbbefeE

c.removeRange(xy1)        // error: 'removeRange' has been renamed to 'removeSubrange'

c.removeSubrange(xy1)        // cbbbefeE
c.removeSubrange(xy2)        // cefeE

メソッド replaceRange(_:with:) は半開区間と閉区間、置換するものが Character 型の文字を要素とする CollectionType 型か String 型の文字列かの4種類になりました。

半開区間閉区間
文字
コレクション
replaceSubrange
(Range<String.Index>, with: C)
replaceSubrange
(ClosedRange<String.Index>, with: C)
文字列replaceSubrange
(Range<String.Index>, with: String)
replaceSubrange
(ClosedRange<String.Index>, with: String)

var z = "012345"
let g: [Character] = ["g", "G"]
let h: String = "hhh"

z.replaceRange(xy1, with: g)        // error: 'replaceRange(_:with:)' has been renamed to 'replaceSubrange'

z.replaceSubrange(xy1, with: g)        // 0gG345("12"を"gG"に置換)
z.replaceSubrange(xy1, with: h)        // 0hhh345("gG"を"hhh"に置換)
z.replaceSubrange(xy2, with: g)        // 0gG345("hhh"を"gG"に置換)
z.replaceSubrange(xy2, with: h)        // 0hhh45("gG3"を"hhh"に置換)



●5.5 集合


・集合の型宣言と初期値

Table5-3 で紹介しているメドッソのほとんどが改名されています。

集合旧メソッド新メソッド
和集合union(_:) -> Setunion(_:) -> Set
unionInPlace(_:)formUnion(_:)
差集合subtract(_:) -> Setsubtracting(_:) -> Set
subtractInPlace(_:)subtract(_:)
積集合intersect(_:) -> Setintersection(_:) -> Set
intersectInPlace(_:)formIntersection(_:)
対称差集合exclusiveOr(_:) -> SetsymmetricDifference(_:) -> Set
exclusiveOrInPlace(_:)formSymmetricDifference(_:)

// 和集合

var a = Set<Int>(0...3)        // {2, 0, 1, 3}
var b = Set<Int>(3...6)        // {5, 6, 3, 4}
var c = Set<Int>(4...7)        // {5, 6, 7, 4}

let z = a.union(b)        // {2, 4, 5, 6, 0, 1, 3}
a.unionInPlace(c)        // error: 'unionInPlace' has been renamed to 'formUnion(_:)'
a.formUnion(c)        // {2, 4, 5, 6, 7, 0, 1, 3}

// 差集合

var d = Set<Int>(0...3)        // {2, 0, 1, 3}
var e = Set<Int>(3...6)        // {5, 6, 3, 4}
var f = Set<Int>(2...5)        // {2, 0, 1, 3}

let y = d.subtracting(e)        // {2, 0, 1}
d.subtractInPlace(f)        // error: 'subtractInPlace' has been renamed to 'subtract(_:)'
d.subtract(f)        // {0, 1}

// 積集合

var g = Set<Int>(0...3)        // {2, 0, 1, 3}
var h = Set<Int>(3...6)        // {5, 6, 3, 4}
var i = Set<Int>(2...5)        // {5, 2, 3, 4}

g.intersect(h)        // error: 'intersect' has been renamed to 'intersection(_:)'
var x = g.intersection(h)        // {3}
g.intersectInPlace(i)        // error: 'intersectInPlace' has been renamed to 'formIntersection(_:)'
g.formIntersection(i)        // {2, 3}

// 対称差集合

var j = Set<Int>(0...3)        // {2, 0, 1, 3}
var k = Set<Int>(3...6)        // {5, 6, 3, 4}
var l = Set<Int>(2...5)        // {5, 2, 3, 4}

var w = j.exclusiveOr(k)        // error: 'exclusiveOr' has been renamed to 'symmetricDifference(_:)'
var w = j.symmetricDifference(k)        // {5, 6, 2, 0, 1, 4}
j.exclusiveOrInPlace(l)        // error: 'exclusiveOrInPlace' has been renamed to 'formSymmetricDifference(_:)'
j.formSymmetricDifference(l)        // {5, 0, 1, 4}

したがって実行例で積集合を取っているメソッドは修正する必要があります。

jset.intersectInPlace(w)        // error: cannot convert value of type '[String]' to expected argument type 'Set<String>'

jset.formIntersection(w)        // ["幽霊"]



Qiita/Swift 3.0のRangeまとめ

Qiita/Swift 3のRange徹底解説

Study Swift/Reverse Array in Swift 2.2/3.0

articles of samekard/Swift2.2からSwift3.0への変換を行ってみて

Developers.IO/[Swift 3] 型名を取得する

大津真 Web/Swift 3 文字列操作(その2)

Qiita/「文字数」ってなぁに?〜String, NSString, Unicodeの基本〜

Medium/Swift・iOSコラム/Swift 3のStringのCharacter Viewを、なぜIntでsubscript出来ないのか分からない

Medium/Swift・iOSコラム/Swift 3のStringのViewに対して、Intでsubscript出来ない理由

詳解Swift 第3版(Amazon)
 






Bose SoundLink around-ear wireless headphones II
0 Comments
Leave a comment
管理者にだけ表示を許可する
Top
0 Trackbacks
Top
Calendar
06 | 2017/07 | 08
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 31 - - - - -
Recent Articles
iTunes


Swift
Categories
Tips
Profile

水月杏香

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

Wish List
WACOM


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

Bose SoundLink around-ear wireless headphones II
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