型の完全理解は可能か?
今回はSwift最大の特長であるプロトコル
0 == 0. 0 // compile error
REPLで次のとおりに入力してみましょう。
var i = 0
i == 0
i == 0.0
macOSでは次のようになります。
Welcome to Apple Swift version 3.1 (swiftlang-802.0.53 clang-802.0.42). Type :help for assistance. 1> var i = 0 i: Int = 0 2> i == 0 $R0: Bool = true 3> i == 0.0 error: repl.swift:3:3: error: binary operator'==' cannot be applied to operands of type 'Int' and 'Double' i == 0.0 repl.swift:3:3: note: expected an argument list of type '(Int, Int)' i == 0.0
(Objective)
node
> var i = 0 undefined > i == 0 true > i == 0.0 true
perl -de 1
main::(-e:1): 1 DB<1> my $i = 0 DB<2> p $i == 0 1 DB<3> p $i == 0.0 1
python
>>> i = 0 >>> i == 0 True >>> id == 0.0 True
irb
irb(main):001:0> i = 0 => 0 irb(main):002:0> i == 0 => true irb(main):003:0> i == 0.0 => true
スクリプト言語で0 == 0.
が成立する理由は厳密にはそれぞれの言語で異なるのですが,0 == 0.
が成立しない理由は明白です。型が一致しないからです。0
はInt
という型で,0.
はDouble
という型になります。そしてSwiftの型は静的。コンパイルの段階でどの変数0 == 0.
は実行すらさせてくれないというわけです。
なぜSwiftでは0
と0.
は別々の型なのでしょう?
別の役割が期待されているからです。
たとえば割り算。Int
とDouble
でそれぞれ/
してみましょう。
1> var i = 42 i: Int = 42 2> i / 10 $R0: Int = 4 3> var d = 42.0 d: Double = 42 4> d / 10 $R1: Double = 4.2000000000000002
かたや4
,4.
。何が違うか。そう,
5> i % 10 $R2: Int = 2 6> d % 10 error: repl.swift:6:3: error: '%' is unavailable: Use truncatingRemainder insteadd % 10 Swift.%:2:13: note: '%' has been explicitlymarked unavailable here public func %(lhs: Double, rhs: Double) -> Double
整数の範囲で%
で出せるのがInt
の/
で,/
。こういった区別がない言語では,==
が楽な代わりにほかで苦労しています。たとえばJavaScriptにはDouble
に相当するNumber
はあってもInt
に相当する型はないので,42 / 10
に相当する演算は(42 / 10) ¦ 0
などとしなければなりません。
引数をそのまま返すだけの簡単なお仕事
ここで,
func noop(){}
これが0番目なら,
JavaScript
function id(x){ return x }
// es6 ならもっと簡単に var id = (x)=>x;
Perl
sub id { @_ }
Python
def id(x):
return x
Ruby
def id(x)
x
end
それではSwiftでは? Swiftは静的型言語
func id(_ x:Int)->Int { return x }
func id(_ x:Double)->Double { return x }
func id(_ x:String)->String { return x }
// ...
こういうのを繰り返し書かなければならないということでしょうか? やってることどころか{}
の中身もまったく同じなのに?
ここで颯爽と登場するのが総称型
func id<T>(_ x:T)->T {
return x
}
何でもござれです。
1> func id<T>(_ x:T)->T { 2. return x 3. } 4> id(0) $R0: Int = 0 5> id(0.0) $R1: Double = 0 6> id("") $R2: String = "" 7> id([0]) $R3: [Int] = 1 value { [0] = 0 } 8> id([0:""]) $R4: [Int : String] = 1 key/value pair { [0] = { key = 0 value = "" } }
ここでidは総称関数T
はプレイスホルダー型