Swiftとは
Wikipedia より
Swift(スウィフト)は、アップルのiOSおよびmacOS、Linuxで利用出来るプログラミング言語。Worldwide Developers Conference (WWDC) 2014で発表された。アップル製OS上で動作するアプリケーションの開発に従来から用いられていたObjective-CやObjective-C++、C言語と共存することが意図されている。
swift.org Language Guide より
Swift is a type-safe language, which means the language helps you to be clear about the types of values your code can work with.
Type-safe
var id: Int = 123
var name: String = "abc"
name = 456 // Compile error: cannot assign value of type 'Int' to type 'String
var ids: Array<Int> = []
ids.append(id)
ids.append("xyz") // Compile
安全に、呼び出し側が指定した型で、Arrayを使用することができる (Generics)
Genericsを使わないと、
class IntStack {
var items = [Int]()
func push(_ item: Int) {
items.append(item)
}
func pop() -> Int {
return items.removeLast()
}
}
var ids = IntStack()
ids.push(id)
ids.push(name) // Compile error: cannot convert value of type 'String' to expected argument type 'Int'
StringStack
など、利用する型ごとにクラスが必要?
Genericsを使うと
class Stack<Element> {
var items = [Element]()
func push(_ item: Element) {
items.append(item)
}
func pop() -> Element {
return items.removeLast()
}
}
var ids = Stack<Int>()
ids.push(id)
ids.push(name) // Compile error: cannot convert value of type 'String' to expected argument type 'Int'
var names = Stack<String>()
names.push(name)
でも逆に、呼び出し元が決めたい場合も
// これを公開し、実際のstructは隠蔽する
protocol ChatRoom {
var id: Int { get }
var name: String { get }
}
// DM: チャットルーム名は参加者名のカンマ区切り、
fileprivate struct DMChat: ChatRoom {
var id: Int
var name: String { memberNames.joined(separator: ", ") }
var memberNames: Array<String>
}
// チーム: 名前やアバターアイコンを持つ
fileprivate struct TeamChat: ChatRoom {
var id: Int
var name: String
var memberIDs: Array<Int>
var avatarIcon: String
}
func loadDMChat(id: Int) -> ChatRoom {
return DMChat(id: id, memberNames: ["Taro"])
}
func loadTeamChat(id: Int) -> ChatRoom {
return TeamChat(id: id, name: "ACCESS", memberIDs: [100,101,102], avatarIcon: "file")
}
loadDMChat()
では ChatRoom
として内部の型は隠蔽したいんだけど、実際に返るのは常に DMChat
。
func loadDMChat(id: Int) -> <C: ChatRoom> C {
return DMChat(id: id, memberNames: ["Taro"])
}
こんな感じに、Reverse Genericsしたい。
Returning an Opaque Type
-func loadDMChat(id: Int) -> ChatRoom {
+func loadDMChat(id: Int) -> some ChatRoom {
return DMChat(id: id, memberNames: ["Taro"])
こう書くことで、コンパイル時にこの戻り値は DMChat
型とみなされる。
// Compile error: cannot convert value of type 'some ChatRoom' to specified type 'DMChat'
private let dm: DMChat = loadDMChat(id: 1)
仮に DMChat
型が呼び出し元に見えていたとしても、その型で受け取ることを許可しているわけではない。
何が嬉しいのか
- 型の隠蔽
- オーバーヘッドがない
- どんなオーバーヘッド?
Value type
var name: String = "abc"
print(name) // abc
var name2 = name
name.append("1")
print(name) // abc1
print(name2) // abc
- 実は、SwiftのStringはStructで、値型
- 値渡し、つまり、メモリの確保、コピーなどが行われれる
- 実際には、Copy-On-Writeなど最適化されていはいる
https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html
In fact, all of the basic types in Swift—integers, floating-point numbers, Booleans, strings, arrays and dictionaries—are value types, and are implemented as structures behind the scenes.
参照型のシャローコピーにより引き起こされる問題(コピー元も変更されてしまう)の解決として、値の変更の容易さや、イミュータブルクラスを都度まるごと作り直すオーバーヘッドを考え、値型がよいという考え方らしい(?)
終わり
参考URL