はじめに
タイトルの通り。面倒なこと全部すっ飛ばしてkotlin脳をSwift脳にコンバートするためにとったメモ。読んだ本はswift実践入門。
あと関係ないですがちょうどFF14の漆黒のヴィランズ終わったところなのでたとえがソレっぽいです。
言語の基礎
変数宣言
val enemyId = 10
var name : String = "フィリア"
let enemyId = 10
var name : String = "フィリア"
ポイント
-
val
->let
になった - 型推論の方法は同じ
- varも同じ
関数周り(関数宣言と_)
fun updateStatus(str:Int, int:Int, dex:Int) = ..
/*呼び出し*/
updateStatus(1,2, dex = 3)
func updateStatus(str:Int,_ int:Int, dex:Int) = ..
/*呼び出し*/
updateStatus(1,2, dex: 3) //OK
updateStatus(1,2,3) //NG
ポイント
- 関数宣言は
fun
→func
に - 第二引数以降は「_」が宣言時についていないと呼び出し時にラベル指定が必須になる
- ラベル指定が
=
→:
に - 参考ページ
null,nullable
val weaponId: Int? = null
val weaponName: String? = "ガンブレード"
val nullWeapon: String? = null
val nonNullWeapon = nullWeapon ?: "ガンブレード"
val connectWeapon = weaponName!! + nullWeapon!!
let weaponId: Optional<Int> = nil
let weaponId: Int? = nil
let weaponName: String? = "ガンブレード"
let nullWeapon: String? = nil
let nonNullWeapon = nullWeapon ?? "ガンブレード"
let connectWeapon = weaponName! + nullWeapon!
ポイント
-
null
->nil
になった - kotlinでは
?
で表現してたOptionalを明示的にOptionalとしても書ける -
?:
は??
になった - 強制アンラップは
!!
→!
- その他は大体同じっぽい?
Optional
let none = Optional<Int>.none
let some = Optional<Int>.some(1)
ポイント
- noneはOptionalで値がないケース、Scalaっぽい?
- someはOptionalで値があるケース、Scalaっぽい?
ジェネリクス的なやつ
fun addDamage<T : Enemy>(enemy: T) = ..
func addDamage<T : Enemy>(_ enemy : T) = ..
ポイント
- 書き方一緒
Listとか
val enemyNames = listOf("フィリア", "ティターニア", "イノセント") //不変リスト
val itemLists = arrayOf("エーテル", "エクスエーテル") //可変リスト
itemLists.add("ハイエーテル")
let enemyNames = ["フィリア", "ティターニア", "イノセント"]
let itemLists = Array<String>()
itemLists.append("エーテル")
itemLists.append("エクスエーテル")
itemLists.append("ハイエーテル")
ポイント
- 不変リストは配列っぽい書き方
- 可変リストはJavaっぽい書き方
連想配列(Dictionary)
val enemyMap = mapOf(Pair(1,"ティターニア"), Pair(2,"フィリア"))
enemyMap[1] //ティターニア
let enemyDic = [1: "ティターニア", 2: "フィリア"]
enemyDic[2] //フィリア
ポイント
- 配列っぽい感じに書く。JSONっぽいかも?
型まわりの制約
val hp:Int = 1234
val mp:Long = hp //NG
val mp:Long = Long(hp) //OK
let hp:Int = 1234
let mp:Int64 = hp //NG
let mp :Int64 = Int64(hp) //OK
ポイント
- kotlinと同じ。型が違ったら代入できない。要キャスト
Tuple
val pair = Pair(1,2)
pair.first //1
let tuple2 = Tuple(1,2)
tuple2.0 //1
let tuple3 = Tuple(1,2,"そろそろFF14ネタ疲れてきた")
tuple3.2 //そろそろFF14ネタ疲れてきた
ポイント
- 2個からTupleになったよ、3個でもTupleだよ。Scalaっぽい
制御文周り
kotlin側はもういいよね...
if文
if value <= 3 {
} else if value >= 3 {
} else {
}
ポイント
- 括弧がないぞー!
if-let
let name = Optional("ティターニア")
if let n = name {
print("名前は\(n)です")
} else {
print(”nameless")
}
ポイント
- letっぽいけどIf文っぽい。特に違和感はない、と思う
guard
fun someFunc() {
val v = -1
require(v > 0)
}
func someFunc() {
let v = -1
guard v > 0 else {
return
}
}
ポイント
- kotlinのrequireと似てる。kotlinはIllegalExp投げるけどSwiftはReturnするだけ
switch,where
let optA: Int? = 1
switch optA {
case .some(let a) where a > 10:
//10より大きく、aが存在
default:
//10以下かaが存在しない
}
ポイント
- whereつけると条件式も追加できるぞ。kotlinなら内側にif書くしかなかったやつ
ループ制御(for,for-calse, while, repeat-while)
for elem in array { //foreachっぽいやつ
print(elem)
}
for case 2..3 in array { //独特
}
while i>3 { //普通
}
repeat {
} while j>3 //いわゆるdo-while
ポイント
- 特になし。そのまんま
制御構文(fallthrough,break,continue,return,throw)
let a = 1
switch a {
case 1:
print("case1")
fallthrough
case 2:
print("case2")
default:
print("def")
}
//出力結果
case1
case2
ポイント
-
fallthrough
を使うと次に制御が飛ばせる。Obj-Cの兼ね合いで仕方なく追加された匂いがプンプンする。基本使用禁止だろう - break,continue,return,throwはkotlinと全く同じ
ラベル
label: for elem in [1,2,3] {
for nestedElem in [12,3,4] {
print("moge")
break label
}
}
ポイント
- kotlinで言うところの
return@~
に近い挙動。指定したlabelのループを抜ける
遅延実行(defer)
var count = 0
fun someFunc() -> Int {
defer {
count++
print("second")
}
print("first")
return count
}
print("call func")
someFunc()
//実行結果
call func
first
second
ポイント
- 関数スコープを抜ける時に実行される。んだけど、これ制御複雑になるから基本禁止では・・?
- 参考になりそうなページ
関数的なやつら
基本構文
func 関数名(引数名1: 型, 引数名2:型) -> 戻り値の型 {
}
ポイント
-
:
が->
になった
デフォルト引数
func greet(user: String = "nameless") {
}
print("hello \(user)")
ポイント
- kotlinと同じ
インアウト引数
func greet(user; inout String) {
if user.isEmpty `
user = "nameless"
}
print("hello\(user)")
}
var user: String = ""
greet(user: &User)
print(\(user))
//実行結果
hellonameless
nameless
ポイント
- いわゆる参照渡し。Obj-Cの名残がプンプンする。つまり闇なので使わない方が良い
可変長引数
func print(strings: String...) {
}
ポイント
- kotlinと同じで
...
をつける
オーバーロード
func getV():Int
func getV(i:Int):Int
func getV():String
ポイント
- 引数違いのオーバーロードの他に、戻り値が違うだけでもオーバーロードできる
クロージャ
基本構文
{(引数名1 : 型, 引数名2 : 型...) -> 戻り値の型 in
//処理
}
let triple = {(x:Int) -> Int in
x * 3
}
let quad = {(x:Int) -> Int in
print(\(x))
return x * 4
}
triple(3) //9
quad(3) //12
let closure:(Int) -> Int
func someFunction(x:(Int)->Int) {}
someFunction(closure)
var lengthCal: (String)->Int
lengthCal = {string in //型推論してくれるぞ
return string.conut
}
lengthCal("abc") //3
let lengthOfString = {(string:String)->Int in
return string.count
}
lengthOfString("abcd") //4
let isEqual:(Int,Int) -> Bool = {
return $0 == $1
}
ポイント
- kotlinで言うところの関数変数っぽいやつ
- 処理が2行以上になるならreturn必須(quad)
- 関数の引数にも使えるぞ!(someFunction)
- 型推論も仕事してくれるぞ(lengthCal)
- もちろん「クロージャを引数にとるクロージャ」もいける。(lengthOfString)
- デフォルト引数は使えないぞ!
- 引数名すら省略できるぞ!(isEqual)
関数引数としてのクロージャと属性指定
基本構文
func 関数名(引数名: @属性名 クロージャの型) {
}
属性
- escaping→引数のクロージャが関数のスコープ外で保持される可能性を示す
- autoclosure→遅延評価を実現するための属性。付けると遅延評価してくれる
トレイリングクロージャ
func execute(param: Int,_ process:(Stirng)->Void) {
}
execute(1, {string in
print($0)
})
execute(1) { string in
print($0)
}
ポイント
- カリー化(部分適応だっけ・・・?)
- AndroidStudioならサジェッションがくるやーつ
型とかその辺の話
struct 構造体名 {
let value = 123
func printVal() {
print(self.value)
}
static let signiture = "send from iPhone"
}
class クラス名 {
class ver signiture = "send form Android"
}
enum 列挙型 {
}
ポイント
- structがあるぞ。structは値渡し、classは参照渡し
- 自身へのアクセスは
this
->self
になってるぞ - structの場合は
companion Object
はないけどstatic
があるぞ。意味はJavaのStaticと同じだ!(変数だけでなくメソッドにも使えるぞ) - 上記の
static
と同じ使い方ができるのがclassプロパティだ。違いはクラスの方はオーバーライドできるぞ!(staticはオーバーライドできない) - クラスとか構造体の中の変数はプロパティと呼んでるぞ、C#と同じだ!
プロパティオブザーバ
var プロパティ名 = 初期値 {
willSet {
//プロパティ変更前に実行される処理新しい値はnewValue変数としてアクセスできる
}
didSet {
プロパティ変更後に実行される
}
}
ポイント
- kotlinにはなかった機能・・・かな、多分。
- 挙動は書かれている通り。ログとか仕込む?
レイジーストアドプロパティ
lazy var インスタンスプロパティ名: 型 = 式
static lazy var インスタンスプロパティ名: 型 = 式
struct SomeStr {
lazy var lazyV: Int {
print("generate lazyV")
return 2
}
}
ポイント
- SomeStrがインスタンス化された時ではなく、lazyVを参照した時に初期化される
- kotlinの
lateinit var
とby lazy
を足して2で割ったような挙動
コンピューテッドプロパティ
var プロパティ名: 型 {
get {
}
set {
}
}
ポイント
- kotlinのやつと一緒
- set省略できる
イニシャライザ
struct Greeting {
let to: String
init(to:String) {
selft.to = to
}
}
struct Greeting2 {
let to: String
init?(to:Optional<String>) {
self.to = to ?? nil
}
}
class Mail {
let from:String
let to:String
let title:String
init(from:String, to:String, title:String) {
//初期化
}
convinience init(from: String, to:String {
self.init(from:from, to:to, title:"mogmeoge")
}
deinit {
//クリーンナップ処理
}
}
let greeting = Greeting("some one")
ポイント
- kotlinの
init
関数とコンストラクタを足して2で割ったような機能。 - 初期化の失敗がある場合は
init?
にする。失敗するときはnilを返す - convinience をつけるといわゆるセカンダリコンストラクタ
- 全て初期化されているならばinit関数は不要(kotlinと同じ)
- deinitはいわゆるonDestroyみたいなやつ。インスタンス破棄時に呼ばれるぞ
サブスクリプト
コレクションの要素へのアクセスに使う
subscript(引数) -> 戻り値の型 {
get {
}
set {
}
}
struct Progression {
var numbers:[Int]
subscript(index: Int)->Int {
get {
return numbers[index]
}
set {
numbers[index] = newValue
}
}
}
ポイント
- なぜコレクションだけ特別扱いしてしまったのか、コレガワカラナイ
エクステンション
fun String.log() {
print(this)
}
"test".log()
extension String {
func log() {
print(self)
}
var enclosedString: String {
return "[ \(self) ]"
}
"test".log()
ポイント
-
extention
修飾子をつける必要がある - もちろん定数に対しても拡張できる
- 参考ページ
型の種類
値渡し、参照渡し
-
struct
→値渡し -
class
→参照渡し
列挙型
enum Weekday {
case sunday
case monday
case tuesday
case wednesday
case thursday
case friday
case saturday
init?(japaneseName: String) {
switch japaneseName {
case "日": self = .sunday
case "月": self = .monday
case "火": self = .tuesday
case "水": self = .wednesday
case "木": self = .thursday
case "金": self = .friday
case "土": self = .saturday
default: return nil
}
}
}
enum 型名: ローバリューの型 {
case ケース1 = ローバリュー
case ケース2 = ローバリュー
..
}
ポイント
- initを用意するとkotlinでparserを書くのとと同じ感じ。こっちの方がスマートか?
- ローバリューは
enum Weekday(val name)
的なやつと一緒.Enumの要素と値を紐づける
プロトコル
いわゆるinterfaceクラス
基本構文
protocol プロトコル名 {
//定義
}
struct 構造体名 : プロトコル1, プロトコル2... {
//中身
}
class クラス名 : スーパークラス名, プロトコル1, プロトコル2 {
クラスの定義
}
extension エクステンションを定義する対象の型 : プロトコル名 {
//定義
}
ポイント
- 素直な感じなのでそのまんま
プロパティ
protocol プトロコル名 {
var プロパティ名: 型 {get set }
}
protocol SomeProtocol {
var id:Int {get}
}
struct SomeStr1: SomeProtocol {
var id:Int
}
struct SomeStr2: SomeProtocol {
let id: Int
}
struct SomeStr3: SomeProtocol {
var id: Int {
return 1
}
}
ポイント
- プロトコルでのプロパティは常にvar(継承先でそこはハンドリングするスタンス)
- setもプロトコルに書かれている場合、
let
には適応できない
メソッド
protocol プロトコル名 {
funcj 関数名(引数) -> 戻りの型
}
protocol SomeProtocol {
mutating func someMutatingMethod()
func someMethod()
}
struct SomeStr: SomeProtocol {
var number:Int
mutaing func someMutatingMethod() -> Void {
number = 1
}
func someMethod() {
number = 1 //コンパイルエラー
}
}
class SomeStr: SomeProtocol {
var number:Int
func someMutatingMethod() -> Void {
number = 1
}
func someMethod() {
number = 1 //OK
}
}
ポイント
- structは値渡しになるので、プロパティを更新するときはmutaingが必要
- classは参照渡しなのでどちらも不要
連想型
protocol プロトコル名 {
associatedtype 連想型名
var プロパティ名: 連想型名
func メソッド名(引数:連想型名)
func メソッド名() -> 連想型名
}
protocol SomeProtocol {
associatedtype AssociatedType
// 連想型はプロパティやメソッドでも使用可能
var value: AssociatedType { get }
func someMethod(value: AssociatedType) -> AssociatedType{
return 1
}
}
//typealiasで指定
struct SomeStr1 : SomeProtocol {
typealias AssiosicatedType = Int
var value: AssosiatedType
func someMEthod(value: AssosicatedType) -> AssociatedType {
return 1
}
}
//自動型推論
struct SomeStr2 : SomeProtocol {
typealias AssiosicatedType = Int
var value: Int
func someMEthod(value: Int) -> Int {
return 1
}
}
// ネスト型AssociatedTypeを定義することで要求を満たす
struct SomeStruct3 : SomeProtocol {
struct AssociatedType {}
var value: AssociatedType
func someMethod(value: AssociatedType) -> AssociatedType {
return AssociatedType()
}
}
ポイント
- ジェネリクスに近い機能。歴史的背景を感じる
- プロトコルって言うくらいだからインタフェースと言うよりも型に依存しない処理だけを表現するのに使うイメージが強い
制約系
protocol プロトコル名 {
associatedtype 連想型名 : プロトコル名またはスーパークラス名 where 連想型の制約
}
protocol Container {
associatedtype Content
}
protocol SomeData {
associatedtype Value
associatedtype ValueContainer: Container where
ValueContainer.Content: Equatable, ValueContainer.Content == Value
}
ポイント
- where句の後ろは連想型の制約を書く
デフォルトの型指定
protocol SomeProtocol {
associatedtype AT = Int
}
ポイント
- protocolの時点で指定する。これでデフォルトはIntになる
プロトコルの継承周り
//プロトコルの継承
protocol プロトコルA : プロトコルB, プロトコルC...{
}
//クラス専用プロトコル
protocol プロトコル名: class {
}
ポイント
- ほぼKotlinと一緒
- structとclassの2つがあるために、クラス専用プロトコルの宣言なんてものがあるぞ
エクステンション
extension プロトコル名 {
実装(Not 定義)
}
extention プロトコル名 where 型制約 {
型制約を満たす場合に有効になるエクステンション
}
ポイント
- 既存のプロトコルに対して実装を
Extension
できる - 型制約をつけた場合、条件を満たした場合のみ使える
標準ライブラリのプロトコル
-
Equatable
-> イコール -
Comparable
-> 比較 -
Iterator
-> イテレータ -
Sequence
-> 要素の列挙のためのプロトコル -
Collection
-> サブスクリプトによる要素へのアクセス -
Encodable,Decodable,Codable
-> エンコード、デコード
ジェネリクス
基本構文
func 関数名<型引数> (引数名: 型引数) -> 戻り値の型 {
}
func someMethod<T> (value:T) -> T {
}
struct 構造体名<型引数> {
}
struct GenericStr<T> {
var property:T
}
class クラス名<型引数> {
}
class GenericClass<T> {
func someFunc(x: T) {}
}
enum 列挙型<型引数> {
}
enum GenericEnum<T> {
case SomeCace(T)
}
ポイント
- kotlinと同じ
- ただしprotocolはassociatedtypeによって型が表現されるため、ジェネリクスが使えるのはstruct,class,enumの3つだけ
型制約
func 関数名<型引数: プロトコル名やスーパークラス名(引数)->戻り値の型 {
}
func 関数名<型引数: プロトコル名(引数)->戻り値の型 where 連想型: プロトコルやスーパークラス {
}
func 関数名<型引数1 : プロトコル1, 型引数2 : プロトコル2>(引数) -> 戻り値の型
where プロトコル1の連想型 == プロトコル2の連想型 {
関数呼び出し時に実行される文
}
ポイント
- kotlinと(ほとんど)一緒
- protocolが特殊運用になってるので、こっちもプロトコルについては特殊な記法になる
- where句の後ろに連想型の制約を記載する
モジュール
考え方はkotlinのマルチモジュールと同じ
アクセス修飾子
-
open
->モジュール内外で全てのアクセスOK -
public
->モジュール内外で全てのアクセスOK。ただしモジュール外での継承やオーバーライドは禁止 -
internal
->同一モジュール内のみ(kotlinのinternalと同じ).デフォルトのアクセスレベル -
fileprivate
->同一ファイル内のみアクセス許可 -
private
->対象の要素が属しているスコープ内のみ許可(kotlinのprivateと同じ)
コメントについて
// 通常コメント
/*
* 通常コメント
*/
/// ドキュメントコメント
/**
* ドキュメントコメント
*/
ポイント
- 通常コメントはkotlinと一緒
- ドキュメントコメントはkotlinで言うところのjavadocに近い. QuickHelpから見えるようになる
型の設計指針
struct or class
- 基本
struct
を使え - structのletがkotlinのvalに当たる。classのletはkotlinのvalと同等では無い。
-
deinit
使いたいときはclassがいいかもよ -
abstract calss
という概念が存在しないので、表現する場合はprotocol
を使う必要がある- abstractクラスとして表現していた「継承先で共通に使える実装」はprotocolのextensionで実装する
- classの継承は共通のストアドプロパティを使いたいときくらいにしか使わない
Optional
- kotlinと同じ設計思想
イベント通知回り
デリゲートパターン
- 普通のデリゲートパターン。protocolで宣言する
- 命名規則は
did<動詞>
とwill<動詞>
で**<動詞>がいつ実行されるか**を表現している. - 慣習的にUIKitで提供されているDelegateは第1引数がデリゲート元のオブジェクトを渡す。これは名前空間としてオブジェクトを区別するため
- だいたいUIKitで提供されるやつがデリゲートパターンになっている
弱参照の解消
weak
を変数の前につけると弱参照になる。弱参照になるとARCの参照カウントが0のまま更新されないようになる。
これはdelegateパターンを使うと第1引数にデリゲート元のオブジェクトを渡すために循環参照になる。そのため、delegateオブジェクトにweak
を作って弱参照にする必要がある。
クロージャ(キャプチャリスト)
{[weak または unowned 変数名または定数名](引数) -> 戻り値 in
//処理
}
class SomeClass {
let id: Int
init(id: Int) {
self.id = id
}
}
let object1 = SomeClass(id:42)
let object2 = SomeClass(id:43)
let closure = { [weak object1, unowned object2] () -> Void in
print(type(of: object1))
print(type(of: object2))
}
closure()
//実行結果
Optional<SomeClass>
SomeClass
ポイント
-
weak
はメモリ解放を前提とした弱参照.メモリ解放が前提(つまりnilの可能性がある)のでOptionalになる。クロージャ内でオブジェクトにアクセスする時点で解放されていたらnilが返る -
unowned
はメモリ解放を想定しない弱参照.つまり参照時点では必ず参照元が存在している前提なのでオブジェクトそのまま。クロージャ内でオブジェクトにアクセスする時点で解放されていたらエラーになる - 使い所はkotlinと同じ感覚でOK。(コルーチンとはちょっと違うかな)
使い分け
循環参照を招かない場合
- クロージャの実行時に参照するインスタンスが必ず存在する→キャプチャリストを使わない
- クロージャの実行時に参照するインスタンスが存在しなくても良い場合→
weak
循環参照を招く場合(大雑把にはclosureの中でselfを参照してるかつclocure外でclosureのインスタンスを保持している)
- 参照するインスタンスが先に解放される可能性がある→
weak
- 参照するインスタンスが先に解放される可能性がない→
unowned
orweak
escaping属性
escapingをつけるとselfが必須になる=循環参照に気付きやすくする。逆に言えばescapingがない=循環参照がない、となる
var c: (() -> Void)? = nil
func execute(_ closure: @escaping () -> Void) {
closure()
c = closure
}
オブザーバー
どっちかってーっとイベントハンドラーの実装に近い。(≠RxのObserver)。イベントハンドラに登録(addObserver)して、登録された同名のイベントハンドラに通知をし(post)、登録されたイベントハンドラに通知を受け取る(handle)、終わったら登録解除(removeObserver)。
割とやりたい放題できるので危険な香りがする。
selectorと@objc
#selector
はObj-Cのセレクタ型のオブジェクトにデータを渡すための修飾子。つけるとselector型になる感じ.クラスキャストに近い?
@objc
はメソッドにつけるとObj-Cからアクセスできるようになる.selectorとセットで使う感じ
# selector(型名.メソッド名)
@objc func メソッド名
class SomeClass {
@objc func someMethod() {}
}
let selector = #selector(SomeClass.someMethod)
非同期処理
RxSwiftでよくね?
エラー処理
Result<T,Error>
,do-catch
,defer
Result<T,Error>
型で返すパターンと、do-catch
で実現するパターンがある。Result
は非同期の処理用、do-catch
は同期の処理用。
do {
defer {
doを抜けたら実行される
}
throw 的な何か
} catch {
エラー処理.定数errorが参照できる
}
ポイント
- Resultは関数型のResultと同じ設計方針で同じ使い方
-
do-catch
は御察しの通りtry-catch
と同じ - deferは
finally
に近い。必ず実行される系(ただしタイミングは違う)
throw
,try
,try!
,try?
func 関数名(引数) throws -> 戻りの型 {
throwの可能性のある処理
}
func someMethod throw -> Int {
throw XXError
}
do {
let i = try someMethod()
} catch {
}
let i = try! someMethod() // Int or エラー
if let i = try? someMethod() {} //Optional<Int>
ポイント
- javaでのメソッドの呼び元にエラーを返すやつ。
- イニシャライザにも使える
- 呼び元はエラーの発生する可能性のあるメソッドを呼ぶ場合は
try
が必要になる -
try!
はエラーが絶対に発生しないぞ!という強い意志のもの実行する。do-catch
が不要になる -
try?
はOptionalが返るようになる。do-catch
は不要になる
rethrow
クロージャーがエラーを吐く場合はrethrow
を使う。
struct SomeError: Error {}
func rethorwingFunction(_ throwingClosure: () throws -> Void) rethrows {
try throwingClosure()
}
do {
try rethorwingFunction {
throw SomeError()
}
} catch {
error // SomeError
}
ポイント
- 普通のthrowと一緒な使い方.
- クロージャがthrow投げるときに使う
fatalError
,Never
func randomInt() -> Int {
fatalError("未実装だぞ")
}
いわゆるアプリ終了系のエラー.`Never`は値を返さず、それ以降の処理を実行しない(ちなみにVoidは空のTupleを返す).
## `assert`,`assertionFailure`
いわゆるアサーション
```swift
func format(minute:Int, second: Int) -> String {
assert(second < 60, "secondは60みまんで")
return "〜〜"
}
func printSeason(month:Int) {
swiftch month {
..
default:
assersionFailure("呼ばれたらダメなやつ")
}
}
ポイント
- assertはリリース時には無効になる
- 実行されたらアプリが終了する
- assertionFailureは呼ばれること自体がNGなやつ