post Image
Never GiveUp というタイトルで Swift Tweets で発表しました。 #swtws

#swtws Never GiveUp.001.png

今回は Swift 3 から登場した Never 型で遊んでみたいと思います。

この記事は Never GiveUp というタイトルで Swift Tweets で発表したツイートをまとめたものになります。

Never 型とは

Never 型は fatalError でも使われる、戻り値がない ことを示す型です。

Swift 2 では @noreturn 属性でしたが、表から『値を返さないこと』が見えにくいため、Swift 3 からは型として明記されることになったみたいです。

/////////////////////////////////////////////////////
//// ⭐️ 生還に期待を寄せてしまうコード (Swift 2)

@noreturn func oneWayTrip() -> Gift? {
}

/////////////////////////////////////////////////////
// ⭐️ 戻り値がないことが明確なコード (Swift 3)
//

func oneWayTrip() -> Never {

    // コンパイラーによって、必ず処理が打ち切られることが保証される。
    // ERROR: Function with uninhabited return type 'MyNever' is
    // missing call to another never-returning function on all paths
}

// この戻り値が Never なので、処理はここまで。
oneWayTrip()

// この行には辿り着き得ない。
print("DONE")       // WARNING: Will never be executed

その実態は、列挙子のない列挙型は値化できない性質を応用して『値が存在し得ないから打ち止め』みたいな表現です。実際の定義は、このようにシンプルなものになっています。

enum Never {

}

Never は、つくれる?

それなら『もしかして自分で作れる?』と思ってみたのが今日のテーマです。

実際、列挙子を持たない列挙型を定義しただけで、標準の Never と同じ動きを見せてくれました。

enum MyNever {

}

func oneWayTrip() -> MyNever {


    // ERROR: Function with uninhabited return type 'MyNever' is
    // missing call to another never-returning function on all paths
}


// ⭐️ 標準の Never と同じ動作になった

oneWayTrip()
print("DONE")       // WARNING: Will never be executed

本当に、値化できない?

ところで本当に値化できないのでしょうか。そう思って標準の Never にイニシャライザーを拡張して使ってみると、右辺を評価したところ打ち切りに。やはり無理みたいです。


extension Never {

    init() {

        self = unsafeBitCast((), to: Never.self)
    }
}

// ⭐️ やっぱりインスタンス化はできない

let never = Never()     // WARNING: Will never be executed

じゃあ、イニシャライザーではなく関数ならどうだろうと試してみたのですけど、やっぱりダメそうですね。関数の呼び出しまでで打ち切りです。

func oneWayTrip() -> Never {

    return unsafeBitCast((), to: Never.self)
}

let never = oneWayTrip()        // WARNING: Will never be executed

でも、もしかしてオプショナルに包んでみたら…? と試してみたら、できました。オプショナルバインディングで Never な値が取れました。子供騙しな感は残りますけれど。

func oneWayTrip() -> Never? {

    return unsafeBitCast((), to: Never.self)
}

if let never = oneWayTrip() {

    print("Success !?", never)          // "Success !? \n"
    print("Type is", type(of: never))   // "Type is Never\n"
}

それなら Any 型は…? と試してみると、大丈夫みたい。入れ物は Any ですが、オプショナルと違ってすぐ使えるし、キャストで正真正銘 Never な値になります。

func oneWayTrip() -> Any {

    return unsafeBitCast((), to: Never.self)
}

// ⭐️ 型は Any 
let never = oneWayTrip()

print("Type is", type(of: never))   // "Type is Never\n"
print("Is Never: ", never is Never) // "Is Never: true\n"


// ⭐️ キャストすると純粋な Never 型の値として使える。
let a = never as! Never

print(a)                            // "\n"

ジェネリック型だとどうでしょう。何かしらの形で Never を指示しないといけないものの、型推論も期待できるので、Never を取る関数にそのまま渡せたりします。

func oneWayTrip<N>() -> N {

    return unsafeBitCast((), to: N.self)
}

let never: Never = oneWayTrip()

print("Never", never)               // "Never \n"
print("Type is", type(of: never))   // "Type is Never\n"


// ⭐️ とりあえず、スマートに Never 型を受け取るところまではできた。
func challange(_ something: Never) {

    print(something)
}

// ⭐️ 奇跡の生還
challange(oneWayTrip())

// ⭐️ 処理が継続
print("DONE")       // "DONE"

おしまい

今回はここまで。Never を自作したり、列挙子を持たない列挙型を値化したりして遊んでみました。これによってどんな世界が広がるのかは分からないですけど、とりあえず面白かったです。

以上、ありがとうございました!

#swtws Never GiveUp.002.png


『 Swift 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。