本稿を書いている真っ最中の3月22日未明
Xcode 7.3 with Swift 2.2
Swift 2.

しかし無変更でコンパイルが通るとはいえ、
typealias UIntType:POUInt
が、
associatedtype UIntType:POUInt
になったり、enum Bit
が廃止予定なのでInt
に変更しろ」
性能、20!/19!
の計算で、BigInt
との速度比較で500倍近くあった速度差が100倍を余裕で切るところまできました。PONSのもくろみはあくまでProtocol-Orientedな数値型を実現することにあり、
Literal Convertible
Swift 2.
var i = 1
正解はInt
です。なぜ? 1
はInt
ですから。では次のd
は?
var d = Double(1)
正解はもちろんDouble
。1
はInt
でもDouble()
に食わせているのですから、Double
になるのはごく自然です。では、x
は?
var x:Double = 1
やはりDouble
です。print(x)
してみると、1.
と表示されます。1
ではなくて。これはどうでしょう?
var y:Double = "1"
今度はerror: cannot convert value of type 'String' to specified type 'Double'
というエラーを出して止まります。しかし、
var z = Double("1")
とすると……、z
には無事、Double
の1.
が代入されるではありませんか。これはいったいどういうことなのでしょう?
「Double
はIntegerLiteralConvertible
プロトコルに準拠しているが、StringLiteralConvertible
プロトコルには標準では準拠していない」
え? 答えになっていない?
では実際にvar d:Double = "1"
を受け付けるようにしてみましょう。リスト1のようなコードをvar d:Double = "1"
の前にペーストしてみてください。するとあら不思議。今度はエラーにならずにd
に42.
が代入されています
extension Double:StringLiteralConvertible {
public init(stringLiteral: String) {
self.init(stringLiteral)!
}
public init(unicodeScalarLiteral: String) {
self.init(stringLiteral: "\(unicodeScalarLiteral)")
}
public init(extendedGraphemeClusterLiteral: String) {
self.init(stringLiteral: extendedGraphemeClusterLiteral)
}
}

リスト1中のLiteral Convertible
とは、IntegerLiteralConverible
なら整数リテラルからの、StringLiteralConvertible
なら文字列リテラルからの、
42.0 + "0.195"
はエラーとはならずに、42.
になってしまうのです。
便利といえば便利ですが、Double
はIntegerLiteralConvertible
であっても、StringLiteralConvertible
でないという仕様は、
42 + 0.195
はエラーとならずに42.
になる一方、
var i = 42 + 0.195
はエラーとなるわけです。
ちなみに、Literal Convertible
プロトコルが存在します。
ArrayLiteralConvertible
BooleanLiteralConvertible
DictionaryLiteralConvertible
ExtendedGraphemeClusterLiteralConvertible
FloatLiteralConvertible
NilLiteralConvertible
IntegerLiteralConvertible
StringLiteralConvertible
StringInterpolationConvertible
UnicodeScalarLiteralConvertible
PONSでは、BigInt
とBigUInt
はIntegerLiteralConvertible
とString LiteralConvertible
に、BigFloat
とRational
はIntegerLiteralConvertible
とFloat LiteralConvertible
にそれぞれ準拠しています。おかげでリスト2のように、
var bq:BigRat = 42.195 // (5938418321153065/140737488355328)
という具合に小数で分数を初期化することも可能になっています。
var bi:BigInt =
"93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000"
ちなみにリスト2のbi
ですが、import PONS
された状態であれば、
(1...100).reduce(BigInt(1),combine:*)
として手軽に生成できます。もしIntegerLiteral Convertible
でなければ、
(1...100).map{ BigInt($0) }.reduce(BigInt(1),combine:*)
のように、Int
を明示的に変換したうえで.reduce
しなければならなかったでしょう。
フィボナッチ数を計算する総称関数も、n < 2
の2
は、Int
ではなくT
なのですが、T(2)
と書く必要はないのです。
func fib<T:POInteger>(n:T)->T{
if n < 2 { return n }
var (a, b):(T, T) = (0, 1)
for _ in 2...n {
(a, b) = (b, a + b)
}
return b
}
Swiftの'ミステリー'
リテラルといえば、String
のリテラルは、""
{}
で囲まれた部分がブロック=関数リテラル、[]
で囲まれた部分が添字またはArray/`
その中にあって異彩を放つのが、'
そうやって見てみると、
本誌最新号をチェック!
Software Design 2022年9月号
2022年8月18日発売
B5判/192ページ
定価1,342円
(本体1,220円+税10%)
- 第1特集
MySQL アプリ開発者の必修5科目
不意なトラブルに困らないためのRDB基礎知識 - 第2特集
「知りたい」「使いたい」「発信したい」をかなえる
OSSソースコードリーディングのススメ - 特別企画
企業のシステムを支えるOSとエコシステムの全貌
[特別企画]Red Hat Enterprise Linux 9最新ガイド - 短期連載
今さら聞けないSSH
[前編]リモートログインとコマンドの実行 - 短期連載
MySQLで学ぶ文字コード
[最終回]文字コードのハマりどころTips集 - 短期連載
新生「Ansible」徹底解説
[4]Playbookの実行環境(基礎編)