LL脳がscalaの勉強を始めたよ その8
Scalaコップ本の第5章に入りますよー、5章は基本型や演算子ですよー
とりあえず今回は5章の前半として基本型とリテラルについてやっていきます
基本型
型の種類
Scalaの基本型を以下に羅列してみる
型のパッケージと単純名
ちなみに、Scalaの基本型はString以外はscala.◯◯というパッケージ(Stringはjava.lang)メンバーだけども、scala及びjava.langは事前にインポートされるので単純名が使えるとのこと。
自分メモ
Charが数値型に含まれるのね…なのにCharのシーケンスのStringは別扱い…うーん、ちょっと引っかかりそうだな
リテラル
What's リテラル
プログラムのソースコード中に使用される定数のことらしい、例えば234や”hogehoge”などがそれにあてはまるみたい。とりあえず定数って覚えておけばいいかしら?
リテラルとしては次の種類がでてきますー
うーん、だいたい基本型と対応してるようなイメージでいいかしらね
整数リテラル
Int, Long, Short, Byteの各型のリテラルで10進数、16進数、8進数の3つの形式がある。
まず16進数(よくhexで表される)を表現する場合は先頭が0xまたは0Xにする必要がある。例として16進数"3a"(10進数で58)を定義してみマス。
scala> val hex = 0x3a hex: Int = 58
次に8進数を表現する場合は先頭が0にする必要がある。例として8進数"75"(10進数で61)を定義してみマス。
scala> val oct = 075 oct: Int = 61
先頭が0以外なら10進数での表現になるのです
scala> val num = 123 num: Int = 123
また、Long型にしたかったら整数リテラルの末尾にLまたはlを付加する
scala> val iLong =123L iLong: Long = 123 scala> val hLong = 0xab834dl hLong: Long = 11240269
ShortやByteは型指定をしてIntリテラルを代入したりする。代入する値が各型の範囲に収まっていればShortやByteとして扱われる
// Shortリテラルの定義 scala> val sInt: Short = 321 sInt: Short = 321 //Byteリテラルの定義 scala> val bInt: Byte = 21 bInt: Byte = 21 // Byteの範囲外の値を突っ込んだら怒られました scala> val bInt: Byte = 321 <console>:4: error: type mismatch; found : Int(321) required: Byte val bInt: Byte = 321
浮動小数点リテラル
浮動小数点リテラルは10進の数字から構成されているけれども、小数点だったりオプションのeがついていることもある。
例えばこんな感じ
// 小数点表記 scala> val big = 1.2345 big: Double = 1.2345 // 対数表記(っていっていいのかしら?) scala> val bigger = 1.2345e1 bigger: Double = 12.345 // eやEの後ろは指数部 scala> val biggerStill = 123E45 biggerStill: Double = 1.23E47
指数部は10のn乗なので[仮数部]e[指数部]の表現だと[仮数部]×(10の[指数部]乗)ってな感じになりマス。うーん、高校数学っぽい。
上の例のように浮動小数点リテラルは標準でDoubleになるので、Floatにしたい場合は末尾にFまたはfを付加する。
scala> val little = 3.21f little: Float = 3.21 scala> val little = 3.21e2F little: Float = 321.0
明示的にDoubleにしたい場合は末尾にDまたはdをつければイイんダヨ
scala> var dlittle = 3.21d dlittle: Double = 3.21 scala> var dlittle = 3.21E2D dlittle: Double = 321.0
大文字・小文字のどちらでもOKだけども、どちらかに統一した方が混乱は防げそうな塩梅ね。コミュニティー的におすすめはどちらなんだろう?
ちなみに、FloatもDoubleも範囲外の値を突っ込む場合は丸めて格納してるっぽいです
// floatで丸め(四捨五入で丸められてる?) scala> var fOver = 1.23456786923456786f fOver: Float = 1.2345679 //Doubleでキリ☆ステ(こっちは切り捨てみたい) scala> var dOver = 1.23456789123456786d dOver: Double = 1.234567891234568
floatとDoubleで丸め処理が違うっぽいんだけども、実際のところはどうなんだろう?そのうち調べてみよう。
文字リテラル
文字リテラルはシングルクォートでUnicode文字を囲んだもの。
よく考えたらScalaで初めてシングルクォート使う気がするんだけど、ここでしか使わないのかしら?
とりあえず例をずらーっと表示
// 普通に文字を指定 scala> val a = 'A' a: Char = A // 8進数(Unicode文字コードポイント)表記も可能 scala> val c = '\101' c: Char = A // 16進数(Unicode文字の一般表現)表記も可能 scala> val c = '\u0041' c: Char = A
どうやら16進数のUnicode文字列はScalaのあらゆるところで使えるみたいで、こんな変態コードもかけます
scala> val B\u0041\u0044 = 1 BAD: Int = 1
変数にUnicode表記を混ぜてます。べ、別に私が作ったんじゃないんだからね、コップ本のサンプルにのってるんだから //
それとエスケープシーケンスで表現される文字列リテラルは下記の通りです
- 改行: \n (\u000A)
- バックスペース: \b (\u0008)
- タブ: \t (\u0009)
- 改ページ: \f (\u000C)
- 復帰: \r (\u000D)
- ダブルクォート: \" (\u0022)
- シングルクォート: \' (\u0027)
- バックスラッシュ: \\ (\u005C)
文字列リテラル
ダブルクォートで囲むだけで、基本は文字リテラルと同じー(Unicode文字は使えないけど)
// 文字列の出力 scala> val hello = "world" hello: java.lang.String = world // エスケープシーケンスも使ってみる scala> val hello = "world \\\"\' wide" hello: java.lang.String = world \"' wide
ただし、エスケープシーケンスが混ざったり、複数行の文字列だったりするとわかりにくくなるので、その場合は次のように書くことができる…まるでPythonのようだ
// エスケープシーケンスがそのまま出力 scala> val hello = """world \\\"\' wide""" hello: java.lang.String = world \\\"\' wide // 改行も許容しますぜ scala> val hello = """world wide""" hello: java.lang.String = world wide
ちなみに、改行を許容するもののスペースもそのままなのでprintlnなんかで出力すると下のように崩れてしまうノデス
scala> println(hello) world wide
表記を崩したくない場合は下記のように"|"を各行頭にいれて、stripMarginメソッドを使いますよー
scala> val hello = """|world |wide""" hello: java.lang.String = |world |wide scala> println(hello.stripMargin) world wide
ちなみにstripMarginは文字列にかかるメソッドなので、こんな感じでもOK
scala> println("""|world |wide""".stripMargin) world wide
シンボルリテラル
(´ε`;)ウーン…さっぱりわからん、でもそれでは進まないので、ワカランなりに自己解釈をつけていこう
まずはシンボル
シンボルはRubyなんかであるシンボルの概念と同じなのかな?Rubyなんかのリファレンスを見ると
シンボルは任意の文字列と1対1に対応するオブジェクト
…とあるので、思い切り雑に言ってしまえばオブジェクトへの参照文字列が”シンボル”って解釈でいいのかしら?
とりあえず上記解釈があっているとすれば、とあるメソッドにオブジェクト名を引数として指定する場合なんかに、型チェックで叩き落とされないようにするためのリテラル→シンボルリテラルって類推することができるなぁ…あってんのか?
そんなオレオレ超解釈でサンプルを読んでいってみる
といった前提をもとに次のような、データベース更新処理を定義する
// レコードフィールドの更新メソッド def updateRecord(r: Symbol, value: Any) { // rで指定されたレコードフィールドについて // valueの値で更新するような具体的な処理 }
実際にuser_nameというフィールドを更新したい場合に、動的型付け言語なら次のように書いてもOKだったりするけどもScalaだとアウトになる
// user_nameが宣言されていない識別子なのでエラー updateRecord(user_name, "Mike")
こういうときにシンボルリテラルを使うのです(`・ω・´) キリ
// user_nameがシンボルだとわかるのでコンパイルを通過 updateRecord('user_name, "Mike")
…ようするにシンボル渡したりなんだりを(動的型付け言語のように)簡潔にするためのリテラルってことでいいですか(´・ω・`)、教えて偉い人
ちなみにシンボルは.nameでアクセスすると名前を見出すことが可能みたい
scala> val s = 'SampleSymbol s: Symbol = 'SampleSymbol scala> s.name res18: String = SampleSymbol
ついでに同じシンボルリテラルを2度以上書いたとしても、どの式も同一のシンボルオブジェクトを参照するらしい…例えば下のような定義のときにs1とs2の指し示す先は同じってことかな?
scala> val s1 = 'SampleSymbol s1: Symbol = 'SampleSymbol scala> val s2 = 'SampleSymbol s2: Symbol = 'SampleSymbol
(´ε`;)ウーン…シンボルリテラルは若干消化不良気味だなぁ…あとは使って慣れるしかないかしら…
Booleanリテラル
True or False OK?
scala> var bool = true bool: Boolean = true scala> var bool = false bool: Boolean = false
以上ー
普段は読む作業(サンプル実行含む)とまとめ作業を別々にやるんだけども、読みながらまとめると流石に時間がかかるなぁ…と実感。休日だからまあいいかしらね。
ということで5章に突入したので次回は演算子だなー、1回じゃ終わらないだろうなー、なー