print(1+2)
@dynamicMemberLookup struct Employee { subscript(dynamicMember member: String) -> String { let properties = ["name": "Taylor Swift", "city": "Nashville"] return properties[member, default: ""] } subscript(dynamicMember member: String) -> Int { let properties = ["age": 26, "height": 178] return properties[member, default: 0] } } let e = Employee() let name: String = e.name // "Taylor Swift" let city: String = e.city // "Nashville" let age: Int = e.age // 26 let height: Int = e.height // 178 let city_wrongType: Int = e.city // 0 let height_wrongType: String = e.height // ""
@dynamicMemberLookup
自体はメッセージ指向のために入れたわけじゃないけど、そういう捉え方をしてみるとおもしろそうってことでしょうか?actor
↓ https://gist.github.com/lattner/31ed37682ef1576b16bca1432ea9f782#part-2-actors-eliminating-shared-mutable-state@IBOutlet
と @IBAction
をつなげてるときは同じ理由で、オブジェクト指向という概念を特定の言語の(俗に「オブジェクト指向」向けと称される)機能から外挿して学ぶのは難しいし、間違った「オブジェクト指向」を創造してしまう危険がある。少し遠回りに思えても、それぞれの考案者自らがその主張を綴った論文を読んで理解を試みるほうがいい。
class Group { ... } class User { ... } let group: Group = ... let owner: User = group.owner owner.age += 1 // 何が起こる?
Group
が内部に保持してるインスタンスをそのまま返してたら Group
の owner
の age
もインクリメントされますけどowner.age += 1
は group
に影響を与えません。 (edited)class User { let name: String let age: Int ... } var user = User(name: "Swift", age: 4) user = user(name: user.name, age: user.age + 1)
(edited)// ミュータブルクラス class User { var name: String var age: Int ... } let user = User(name: "Swift", age: 4) user.age += 1 // 楽
(edited)struct
でやると // struct struct User { var name: String var age: Int } var user = User(name: "Swift", age: 4) user.age += 1 // 楽
(edited)mutating func
とかおもしろいですよね。mutating func
と inout
が使いやすさのキーになってる気がしててview.frame.origin.x += 10;
とか。 (edited)view.frame.origin.x += 10;
はコンパイルエラー
(edited)CGRect frame; frame.origin.x += 10;
はOK 話外れました (edited)reduce(into:...)
も追加されたのは Swift 4 で https://github.com/apple/swift-evolution/blob/master/proposals/0171-reduce-with-inout.mdmutating func
とか inout
は機能としてはあったけど、reduce(into:...)
って inout
な引数を持つ高階関数(メソッド)ですけどlet idToUser = users.reduce(into: [:]) { idToUser, user in idToUser[user.id] = user }
(edited)inout
)って時代遅れの遺物的な扱いされてた(主観)けど、値型で見事に活用されてるのとかもおもしろいと思います。inout
は概念上は call by copy-restore です。 inout
で渡せますが当然参照できないので、 get で読み出されて set で書き戻されます。mutating func
であっても、コールバックで self
を書き換えることはできないですし、 mutating func foo() { DispatchQueue.main.async { self.bar += 1 // できない } }
async/await
で結構問題になる気がしててmutating func foo() async { await baz() self.bar += 1 // コンパイルエラー }
(edited)mutating func
なのに self
変更できないのとか、初見でとまどいそう。inout
だと自分同士でできない。 // ミュータブルクラス func sendMoney(from user1: User, to user2: User) { user1.money -= 100 user2.money += 100 } sendMoney(from: user1, to: user2) // OK sendMoney(from: user1, to: user1) // OK
// struct func sendMoney(from user1: inout User, to user2: inout User) { // これ自体は OK user1.money -= 100 user2.money += 100 } sendMoney(from: &user1, to: &user2) // OK sendMoney(from: &user1, to: &user1) // コンパイルエラー
var
と let
の間にもうちょいなんかほしいなーと思うことはあって、 struct User { let name: String var age: Int } do { let group = Group( id: 1, owner: User(name: "hoge", age: 16) ) // groupがletなのでこれはできない // group.owner.age += 1 } // というのはいいんだけど do { var group = Group( id: 1, owner: User(name: "hoge", age: 16) ) group.owner.age += 1 print(group) // Group(id: 999, owner: __lldb_expr_1.User(name: "ほげほげぴよぴよーー", age: 65536)) // 👆!!?? } // 実はこうなってました struct Group { let id: Int var owner: User { didSet { self = Group(id: 999, owner: User(name: "ほげほげぴよぴよーー", age: 65536)) } } }
sendMoney(from: &user1, to: &user1) // コンパイルエラー
は、 @rintaro さんの話を聞いてから見ると納得感はありますね。print("hello world")
(edited)print("Hello world")
print("hello, world")
print("hello world")
print("Hello World!")
print("hello world")
print("hello world")
print("Hello World")
print("hello")
swift print("hello")
print("Hello World")
テストprint("Hello World!")
print("Work from home")
print("Hello World!")
print("Hello, World!")
print("Hello!")
print("Hello, world!")
print("Hello world")
print("Hello World")
print("Hello World!")
print("Hello, World!")
print("ハローワールド")
print("Hello World")
print("Hello world")
Usage: @swiftbot [--version=SWIFT_VERSION] [--command={swift, swiftc}] [--options=SWIFTC_OPTIONS] ``` [Swift Code] ``` Examples: @swiftbot ``` print("Hello world!") ``` @swiftbot --version=4.0.3 ``` print("Hello world!") ``` @swiftbot --command=swiftc --options=-dump-parse ``` print("Hello world!") ``` @swiftbot --platform=mac ``` print("Hello world!") ``` Subcommands: @swiftbot versions: show available Swift toolchain versions @swiftbot contribute: show repository URLs @swiftbot help: show help
print("Hello World")
swift print("Hello World")
print("Hello world!")
Usage: @swiftbot [--version=SWIFT_VERSION] [--command={swift, swiftc}] [--options=SWIFTC_OPTIONS] ``` [Swift Code] ``` Examples: @swiftbot ``` print("Hello world!") ``` @swiftbot --version=4.0.3 ``` print("Hello world!") ``` @swiftbot --command=swiftc --options=-dump-parse ``` print("Hello world!") ``` @swiftbot --platform=mac ``` print("Hello world!") ``` Subcommands: @swiftbot versions: show available Swift toolchain versions @swiftbot contribute: show repository URLs @swiftbot help: show help
swift print("Hello world!")
print("hello world")
print("Hello")
Usage: @swift52 [SWIFT_OPTIONS] ``` [Swift Code] ```
print("Hello world")
(edited)Usage: @swift52 [SWIFT_OPTIONS] ``` [Swift Code] ```
Usage: @swift52 [SWIFT_OPTIONS] ``` [Swift Code] ```
Usage: @swift52 [SWIFT_OPTIONS] ``` [Swift Code] ```
print("hello world")
Usage: @swift52 [SWIFT_OPTIONS] ``` [Swift Code] ```
print("test")
Usage: @swift52 [SWIFT_OPTIONS] ``` [Swift Code] ```
Usage: @swift52 [SWIFT_OPTIONS] ``` [Swift Code] ```
print("Hello!!")
print(1 + 2 + 3 + 4 + 5)
swift print(""" _人人人人人人人_ > 無限ループ <  ̄Y^Y^Y^Y^Y^Y^Y^ ̄ """)
_人人人人人人人_ > 無限ループ <  ̄Y^Y^Y^Y^Y^Y^Y^ ̄
Usage: @swift52 [SWIFT_OPTIONS] ``` [Swift Code] ```
print("Hello WOrld!")
print("hello")
Usage: @swift52 [SWIFT_OPTIONS] ``` [Swift Code] ```
Usage: @swift52 [SWIFT_OPTIONS] ``` [Swift Code] ```
fatalError()
Fatal error: file <stdin>, line 1 Current stack trace: 0 libswiftCore.so 0x00007ff43dc62490 swift_reportError + 50 1 libswiftCore.so 0x00007ff43dcd3b50 _swift_stdlib_reportFatalErrorInFile + 115 2 libswiftCore.so 0x00007ff43d9e954e <unavailable> + 1385806 3 libswiftCore.so 0x00007ff43d9e9157 <unavailable> + 1384791 4 libswiftCore.so 0x00007ff43d9e9782 <unavailable> + 1386370 5 libswiftCore.so 0x00007ff43d9e7a20 _assertionFailure(_:_:file:line:flags:) + 520 7 swift 0x00000000004f5d3e <unavailable> + 1006910 8 swift 0x00000000004fa5b2 <unavailable> + 1025458 9 swift 0x00000000004e7d6c <unavailable> + 949612 10 swift 0x00000000004dca99 <unavailable> + 903833 11 swift 0x00000000004d2abb <unavailable> + 862907 12 swift 0x00000000004cf72d <unavailable> + 849709 13 swift 0x0000000000459672 <unavailable> + 366194 14 libc.so.6 0x00007ff43fd0d740 __libc_start_main + 240 15 swift 0x00000000004591c9 <unavailable> + 365001 Stack dump: 0. Program arguments: /usr/bin/swift -frontend -interpret - -disable-objc-interop -I /Libraries/.build/x86_64-unknown-linux-gnu/debug -I /Libraries/.build/checkouts/SwiftBacktrace/Sources/CSwiftBacktrace/include -I /Libraries/.build/checkouts/SwiftBacktrace/Sources/Clibunwind/include -I /Libraries/.build/checkouts/swift-nio/Sources/CNIOHTTPParser/include -I /Libraries/.build/checkouts/swift-nio/Sources/CNIOSHA1/include -I /Libraries/.build/checkouts/swift-nio/Sources/CNIOAtomics/include -I /Libraries/.build/checkouts/swift-nio/Sources/CNIODarwin/include -I /Libraries/.build/checkouts/swift-nio/Sources/CNIOLinux/i
print("hello world")
Usage: @swift52 [SWIFT_OPTIONS] ``` [Swift Code] ```
print("hey!")
swift print("Hello World")
Usage: @swift52 [SWIFT_OPTIONS] ``` [Swift Code] ```
print("rm -rf /")
print("Hello WOrld!")
print(111)
hello world
hello world
<stdin>:1:6: error: consecutive statements on a line must be separated by ';' hello world ^ ; <stdin>:1:1: error: use of unresolved identifier 'hello' hello world ^~~~~ <stdin>:1:7: error: use of unresolved identifier 'world' hello world ^~~~~
print("はろー")
print("はろー")
swift-5.2-RELEASE
はろー
hello world
<stdin>:1:6: error: consecutive statements on a line must be separated by ';' hello world ^ ; <stdin>:1:1: error: use of unresolved identifier 'hello' hello world ^~~~~ <stdin>:1:7: error: use of unresolved identifier 'world' hello world ^~~~~
git clone git@github.com:refactoring-challenge/reversi-ios.git
途中から来られた方向け: ・今日は音声のみです。画面はありません ・チャンネルリストの下の方にある「音声チャット」に 🔊swift-zoomin というのがあります。そちらにお入りください ・このテキストチャンネルもコードを共有したり、補助的に使用します 今回のリポジトリはこちら。clone して実行してみてください https://github.com/koher/refactoring-challenge-reversi-ios 何かわからないことがあれば音声かこのチャットで遠慮なく聞いてください
public enum Disk { case dark case light }
// 3 列目・ 4 行目のセルの状態を取得 let disk: Disk? = boardView.diskAt(x: 3, y: 4) // 3 列目・ 4 行目のセルを黒のディスクが置かれている状態に変更 boardView.setDisk(.dark, atX: 3, y: 4, animated: false)
boardView.setDisk(.dark, atX: 3, y: 4, animated: true) { isFinished in // アニメーション完了時に呼ばれる }
extension ViewController: BoardViewDelegate { func boardView(_ boardView: BoardView, didSelectCellAtX x: Int, y: Int) { // x 列目・ y 列目のセルがタップされたときに呼ばれる } }
enum VerticalIndex: Int { case one = 0 case two case three case four case five case six case seven case eight }
// Immutable 最高! // index がはみ出さないことを、初期値を Index で保証しているから、force unwrap しても安心だね!
protocol Foo { associatedtype PublisherType: Publisher where Output == Bar var bar: PublisherType { get } }
BoardView.diskAt
のfunc丸ごと消してコンパイルエラーを起こすことから始めました ここで起こったコンパイルエラーを新しく作る盤面管理するやつ使ってコンパイルエラー直してやる予定BoardView
のAPIをprotocolに切り出して、ロジックを具体的な BoardView
から切り離してみたいと思ったけど、 placeDisk
がいやらしい var board: Board = Board(""" -------- x------- -o------ --ooo--- ---ox--- -----oox ---ooo-- --o-x--- """) do { try board.place(.dark, atX: 4, y: 5) XCTAssertEqual(board, Board(""" -------- x------- -x------ --xoo--- ---xx--- ----xxxx ---oxo-- --o-x--- """)) } catch let error { XCTFail("\(error)") }
width
や xRange
が static let
でなかったからなんですよね static let
でないと、インスタンス毎に違う場合がある(今回は8x8でない盤面が今後追加される計画がある)のではないかと勘繰ってしまうpublic enum State: Equatable { case beingPlayed(turn: Disk) case over(winner: Disk?) }
let board: Board = Board(width: 6, height: 4) XCTAssertEqual(board, Board(""" ------ --ox-- --xo-- ------ """))
public struct Board { // ... public init(width: Int, height: Int, disks: [Disk?]? = nil) { precondition(width >= 2, "`width` must be >= 2: \(width)") precondition(height >= 2, "`height` must be >= 2: \(height)") precondition(width.isMultiple(of: 2), "`width` must be an even number: \(width)") precondition(height.isMultiple(of: 2), "`height` must be an even number: \(height)")
enum Player { case human case computer }
struct Board { var discs: [Disc?] = [ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, .white, .black, nil, nil, nil, nil, nil, nil, .black, .white, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, ] }
var 🎲: Int { (1 ... 6).randomElement()! } print(🎲) print(🎲) print(🎲)
var 🎲: Int { (1 ... 6).randomElement()! } print(🎲) print(🎲) print(🎲)
enum Disk: CaseIterable
sides
はCaseIterableで良さそう override func viewDidLoad() { super.viewDidLoad() boardView.delegate = self messageDiskSize = messageDiskSizeConstraint.constant do { try gameManager.loadGame() } catch _ { gameManager.newGame() } updateUI() }
let directions = [ (x: -1, y: -1), (x: 0, y: -1), (x: 1, y: -1), (x: 1, y: 0), (x: 1, y: 1), (x: 0, y: 1), (x: -1, y: 0), (x: -1, y: 1), ] ... for direction in directions {
// MARK: Reversi logics
^ とにかくここをなくす、のが私は重要だとみたcountDisks
だけなくせた(lldb) e print(self.gameState.serialized) o11 xxxxxxxo -ooooxxo ooxoxoxx ooxxooxx oxxxxoxx xxxxoxxx xxoxxxxx xxxxxxxx
class func animate(withDuration duration: TimeInterval, animations: @escaping () -> Void, // ここ completion: ((Bool) -> Void)? = nil)
@escaping
じゃないといけないの?