noyのブログ

健康なエンジニアを目指す人のブログ

脳を目覚めさせる簡単な方法とは?

f:id:noy72:20180709134657j:plain

「脳が目覚めるたった1つの習慣」という本を読みました。著者は東北大学脳科学センター教授の瀧 靖之氏で、脳の健康や賢い子を育てるというテーマの書籍も書かれております。

瀧 靖之『脳が目覚めるたった1つの習慣』、2016年、かんき出版

主観的幸福を追え

主観的幸福とは「自分が感じる幸福」のことであり、世間一般に言われているような幸福ではありません。本書のタイトルである「1つの習慣」は本書では以下のように説明されています。

簡単に言うと、「自分にとって心地いいことや楽しいことを積極的にやる」ということです。(p.23)

幸福な人は仕事のパフォーマンスが高く、クリエイティブで、健康で寿命が長いというデータがあるそうです。仕事ができてクリエイティブな人が幸せになるんじゃないの? という鶏卵的な疑問が出てきますが、幸福が先なようです。もちろん、幸福->能力アップ->幸福->……のような正の循環はありそうですが。

これは脳の特性から考えると理にかなっていることのようです。自分が興味を持てることしか十分に成果を出せないという性質のためだそうです。

好きなことをやることで脳が目覚める、とは非常にシンプルですね。

自分を幸せにするものを見つけるためには

世間の価値観ではなく、自分が真に重要だと思うものを見つけるために注目すべきポイントは以下の二つです。

好奇心を満たしながら生きる

好奇心を満たすといってもそんなことをする時間がない、そんなに楽しいことばかりではない、という問題が出てきます。しかし、それでは脳力を発揮することができません。

好奇心を持つ簡単な方法は、「自分なりのメリット」を見出すことです。

「あらゆる物事にメリットを見出す習慣」は、意識すれば簡単に身につきます。(p.53)

急にメリットを見出せと言われても難しいかもしれませんが、繰り返せば身につくようです。

コミュニケーションを楽しむ

そもそも人間は他者とのコミュニケーションに喜びを感じるようにできているようです。また、多様な人間関係が重要なのは言うまでもないですね。 相手とコミュニケーションをとろうと思ったら、相手を理解したり、関心を持たないといけません。相手に対して好奇心を発揮するとも言えます。

脳を柔軟にする方法の一つとして、「他者を褒める」ことが挙げられています。また、脳の活性化に恋愛もいいらしいです。

ただ、脳の活性化のために恋愛したい、とか言っていると恋愛できなさそうですね(笑)

その他の内容

まとめ

この本のタイトルである『脳が目覚めるたった1つの習慣』とは、「主観的幸福度を上げる選択をして、積極的に行動すること」。つまり、自分のために生きていい、幸せになってもいいのだという許可を脳に出してあげるということでした。(p.210)

注目すべきポイントは好奇心、コミュニケーション。それに加え有酸素運動。また、悪いストレスは避ける。 好奇心を持つことで脳が働くようになるため、自分がやっていることのメリットを見出すようにする。

ちなみに、主観的幸福のために行動するのはいいですが、幸福を追うと不幸になると言われています。
参考:ハーバード研究者「幸福なんか目指すより他にやることがあるだろう!」 _ パレオな男

どういうこっちゃと思うかもしれませんが、大事なのは「価値観に沿って動く」ことです。 価値観に沿って動く=主観的幸福度を上げる

自分の価値観を正しくわかっていない状態で幸福を追っても意味がない、ということでしょうかね。

全肯定ハ◯太郎 LINE bot を作る [初心者向け]

f:id:noy72:20180723115253p:plain

LINE botを作ります。オウム返しができるようになれば、あとはおまけみたいなもんです。全肯定要素はおまけです。

qiita.com

上記の内容をほぼそのまんまやります。

準備

インストール

gem install bundler
bundle init

決まったフォーマットで提供されるRuby言語用のライブラリを「gem」と呼びます。 (中略) gem同士の互換性を保ちながら各gemの導入、管理を行ってくれるのがBundlerです。
(Bundlerの使い方より引用)

カレントディレクトリ直下に GemFile が生成されます。

Gemfileに追加した 4 つのライブラリをインストールします。

bundle

サーバの起動

Rubyのファイルを作ります。

touch app.rb

app.rbに下記を追加。

5 行目の文字列はなんでも良いです。

sinatraを起動。

bundle exec ruby app.rb

http://localhost:4567 をブラウザで開きます。 true が表示されればOKです。

LINE bot の準備

次に、 src/line.rb を作ります。

mkdir src
touch src/line.rb

line.rb の中身は GitHub - line/line-bot-sdk-ruby: Line: :API - SDK of the LINE Messaging API for Ruby. の usage をコピペします。

app.rbに1行追加します。

config.ru を作ります。

heroku での設定

クラウド・アプリケーション・プラットフォーム | Heroku でアカウントを作成します。 

アカウント作成後、右上のアイコン -> account setting -> ssh key で ssh key を登録します。 ※後でもいい

harokuで使うものをインストールします。
(参考: The Heroku CLI | Heroku Dev Center)

brew install heroku/brew/heroku

コンソールからログインします。

heroku login

その後、メールアドレスとパスワードの入力を促されます。ssh key が未登録だと、この段階で設定します。
参考:Heroku導入メモ · GitHub

ログインできたらアプリケーションを作成します。

heroku create zenkoutei-line-bot

作成したら、準備しておいたファイル群をデプロイします。

heroku git:remote -a zenkoutei-line-bot
git add .
git commit -m "First commit"
git push heroku master

https://[アプリ名].herokuapp.com/ に true が表示されればOKです。 表示されない場合は、
- heroku のサイトからデプロイができているかを確認
- サーバを一旦停止させてみる(無意味かも)
とかやってみるといいかもしれません。

LINE bot を作る

LINE Developers に登録します。

登録後、ここ から、

今すぐ始めよう
→ 新規プロバイダー作成
 → 新規チャネル作成

多分、名前にハイフンはダメ。プランはフリーでいいと思います。

これで何もしないbot が作成できました。

環境変数の設定

先ほど作成したページのチャネル基本設定にChannel Secret とアクセストークンがあるので、heroku に登録します。

heroku で作成したアプリのページ
→ 歯車アイコン
 → Config vars

以下のようにします。

f:id:noy72:20180723114839p:plain

オウム返し bot

作成した bot を LINE で友達に追加し、実際にメッセージを送ってみます。 うまくできていれば、送ったメッセージをそのまま返してくれます。

あとは、好きに line.rb をいじってください。

おまけ

全肯定させる

元ネタ:https://togetter.com/li/1233070

line.rb を少しいじります。

replyText メソッドでパターンマッチを用いて全肯定させます。正規表現がわかってない感じがありますが、それっぽく動きます。

正規表現参考

class MatchData (Ruby 2.5.0)

Ruby 正規表現の使い方

結論

Oneshotは良ゲー

7つの言語 7つの世界 ~ Ruby の柔軟性を見よ

f:id:noy72:20180720205219j:plain

最近、『7つの言語 7つの世界』を読んでいます。Ruby, Scala のように広く知られている言語から、Io, Prolog などのあまり見たことがないような言語まで、計 7 つの言語の特徴を紹介するという本です。技術書ではなく読み物に近いです。単に読むだけでは面白くないので、少しだけですが実際に言語を触ってみました。

私自身は C++Java をほんのちょっとだけ触った程度です。

第2章は Ruby です(第1章は、はじめに)。

特徴

If it walks like a duck and quacks like a duck, it must be a duck

つまりどういうこと?

test関数でoutputを呼んでいる。このとき、test関数にどのようなインスタンスを渡しても、output関数さえ持つなら期待された通りに動く。

C++のテンプレートを使って書くと以下のようになる。

つまるところ、必要な機能を持っているのならば、それは期待されているオブジェクトとして見なすことができるということ(自信なし)。

長所

短所

  • パフォーマンス
    そもそもパフォーマンスを重視している言語でない。
  • 平行性とOOP
    これは Ruby に限った話じゃない気がする。
  • 型の安全性
    動的型付けだから仕方ない。

1日目

セルフスタディ

探してみよう

  • Ruby の範囲に関する情報 (p18)

範囲ってスコープのことかな? - 変数と定数 (Ruby 2.5.0)

試してみよう

文字列 "Hello, world" を出力する。

いつもの。

文字列 "Hello, Ruby" の中の "Ruby" という単語のインデックスを検索する。

Stringクラスにあるindexメソッドを使えば良い。

自分の名前を10回出力する

いくつか方法がある。forでもwhileでも当然書ける。
timesはFixnumのメソッドで、Fixnum回ループする。

ファイルに格納されている Ruby プログラムを実行する。

乱数で生成した数字と入力された数字を比較する

printは改行せずに出力する。出力を複数行う場合はコンマで区切る。
改行コードは "\n" で、 '\n' では改行しない。シングルクォーテーションは式を展開しないため、単なる文字列として表示してしまう。

2日目

配列

irb(main):001:0> a = []
=> []
irb(main):002:0> a[0] = 12345
=> 12345
irb(main):003:0> a[1] = "asdf"
=> "asdf"
irb(main):005:0> a[3] = [1,2,3]
=> [1, 2, 3]
irb(main):006:0> a
=> [12345, "asdf", nil, [1, 2, 3]]

配列に複数の型を次々と追加できる。怖い。

irb(main):001:0> a = [1,2,3]
=> [1, 2, 3]
irb(main):002:0> a.push('a')
=> [1, 2, 3, "a"]
irb(main):003:0> a.pop
=> "a"
irb(main):004:0> a
=> [1, 2, 3]
irb(main):005:0> a.pop
=> 3
irb(main):006:0> a
=> [1, 2]

配列は順序付きコレクションなので幾つかのメソッドが使える。
参考:Array - Rubyリファレンス

irb(main):001:0> a = [1, 2, 3]
=> [1, 2, 3]
irb(main):002:0> a[0]
=> 1
irb(main):003:0> a[-1]
=> 3

セグフォではない。 シンタックスシュガーのおかげ。

ハッシュ

irb(main):001:0> num = {1 => "one", 2 => "two"}
=> {1=>"one", 2=>"two"}
irb(main):002:0> num[1]
=> "one"
irb(main):003:0> num[2]
=> "two"
irb(main):004:0> num = {:array => [1, 2, 3]}
=> {:array=>[1, 2, 3]}
irb(main):005:0> num[:array]
=> [1, 2, 3]

C++で言う所の map。Value と Key はなんでも良い。

コードブロック

コードブロックとは名前のない関数である。do ~ end 、あるいは {} で囲うことでコードブロックになる。

前述した times を利用したコード、

これは、"noy"という文字列を表示するというコードブロックを 10 回実行している。

出力
name
noy

main -> pass_block -> call_back と、二つのputsを持つコードブロックが渡されている。

ラムダ式みたいな感じ?

Mixin

モジュールという関数と定数の集まりをクラス混ぜ込むことで、クラスは混ぜ込まれた振る舞いと定数を持つ。

この例では、output モジュールは get の返り値を出力する。ここで、get がいったいなんなのかは書かれていない。Java であればインタフェースが必要になるが Ruby はダックタイピングがあるためインタフェースがいらない。

Output モジュールが混ぜ込まれた Number クラスは、値を出力する out メソッドを持っている。モジュールを混ぜ込むことで機能を追加することができる。

Javaで書くとこうかな?

あれ、インタフェース……

セルフスタディ

探してみよう

配列からハッシュへ、ハッシュから配列へ

参考:ハッシュに含まれるキーや値を配列として取得 - ハッシュ - Ruby入門
参考:配列からハッシュを作成する - ハッシュ(Hash)クラス - Ruby入門

ハッシュの各要素を繰り返す

参考:ハッシュに対する繰り返し - ハッシュ - Ruby入門 

配列で実現可能なデータ構造

計算量を考えないのであれば、
- スタック (pop, push)
- キュー (drop, push)
- デック (unshift, push, drop, pop)

insert や delete も使えるから、割となんでも実現できそう。

やってみよう

ファイル内で、ある文字列を含む行を表示する簡易 grep を作る

ruby grep.rb data.txt 0719

ARGVにコマンドラインの引数が入る。一つ目でファイルを指定、二つ目で探す文字列を入力する。あとは1行ずつ読み出して、indexメソッドで判定する。探す文字列が含まれていない場合は nil が返る。

3日目

オープンクラス

Numeric クラスは数値を表すクラスで、Integer や Float クラスのスーパークラスである。よって、Numeric クラスに tax メソッドを追加すると、Numeric クラスのサブクラスは tax メソッドを使うことができる。

同じ名前のクラスが二つ以上ある場合でも実行できる。上記の例では、Text クラスは initialize メソッド、 tax メソッド、 sale メソッドを持つ。

このように、クラスが一度定義されると、それ以降の同じ名前のクラスは 変更(メソッドの追加など) を行う。

クラス名、メソッド名、メソッドのシグニチャが全てば同じであれば、単に上書きする。

method_missing

method_missingは、存在しないメソッドが呼ばれた時の動作を定義する。上記の例では、メソッド名に含まれる文字をソートした配列を返す。

存在しないメソッドを読んでもエラーを返さなくなる(代わりに method_missing メソッドが呼ばれる)ので、デバッグが難しくなる恐れがある。

参考:method_missing - Rubyリファレンス

セルフスタティ3日目

試してみよう

上記のプログラムを変更し、

というAPIを使えるようにせよ。

とりあえず、CSVファイルを読み取るようにする。each メソッドで table.each を使いファイルの中身を舐める。CSV::Row クラスで method_missing を定義し、CSV::Row.[key] と書かれたら、シンボル key をキーにする(わかりにくい)バリューを返す。

多分、書籍が想定した問題と違うことをしている。

所感

C++Javaと比べて柔軟性がかなり高いと思った。割となんでもできる。動的型付けの言語はほとんど触ったことがなかったので、型がバラバラすぎない……? 考えなさすぎじゃない……? とやってはいけないことをしている気分になった。あと、計算量どうなるのという不安も。

静的型付け -> 動的型付け 「型がなくて不安だけど楽」
動的型付け -> 静的型付け 「柔軟性なさすぎ。。もうマジ無理。。」
ってなりそう。

コミュニティ大きいし、web系に使えるし、使いやすいと思うので、とても良いと思いました(小並感)。

(クソコード) 変数宣言と同時に標準入力を受け取りたい [C++編]

得られる情報はないです。

二つに分かれる

C++ で標準入力をするなら、どのようなコードを書きますか?
cinを使うのであれば、

int a;
cin >> a;

このように書けば良いですね。基礎中の基礎です。

時々、

int a; cin >> a;

のように、改行しない一行のコードを見ることがあります。気持ちはわかります。

どうにかして、変数の宣言/入力をまとめてできないでしょうか。

in()でもできない

cinしてその値を返すだけの関数を作ってみるとどうでしょうか。

int in(){
  int x;
  cin >> x;
  return x;
}

これを使えば変数宣言から入力までをまとめて行えます。
in関数で普通にcinしてますが

int a = in();

問題点は 型がintでなければ使えない ことです。

template<typename T> T in(){
  T x;
  cin >> x;
  return x;
}

テンプレートを使うことで型の問題は解消されますが、残念なことにタイプ数が増えます。

int a = in<int>();
double b = in<double>();

各型についてin関数を作るという方法もありますが、それはなんかいやなのでしません。 どうにかして型名を書くのを避けられないでしょうか?

そしてクソコードへ

class Void{ public: Void() { } }
const Void IN;

class Int{
private:
  int value;
public:
  Int() { }
  Int(Void IN){
    int x;
    cin >> x;
    value = x;
  }
}

int main(){
  Int a(IN);
}

いろいろなものを犠牲にすることで宣言と入力をまとめて行えるようになりました。 入力部分のみに着目すると、タイプ数を3文字(全体の23%)削減することができます。

各型ごとにクラスが必要になるから手間が増えただけ

このままだとvalueにアクセスする手段がないので(publicにしたりget()を作ってもいいですが)、以下の変換関数をクラスに加えておきます。

operator int() const { return value; }

すると、あたかもintであるかのように扱えるようになります。
参考:https://msdn.microsoft.com/ja-jp/library/wwywka61.aspx

  Int a(IN);
  cout << a << endl; // OK
  cout << a + 10 << endl; // OK

それができたからといってどうにもならないですが。

クイズ

突然ですがクイズです。以下の文はどのように動くでしょうか。

vector<Int> a(5, IN);

正解は、「一度だけ入力を受け取り、その値を使って全ての要素を初期化する」でした。

vectorもまとめたい

vectorの宣言と同時に複数の入力を受け取る、ということも実現したかったのですがその方法が思いつきませんでした。

in関数を使えばできます。ただし、型名を書く必要はありますが。

以下の入力を受け取るとします。全てintに収まる整数です。

N
A_1 A_2 ... A_N
template<typename T> T in(){
  T x;
  cin >> x;
  return x;
}
template<typename T> vector<T> in(int n){
  vector<T> x(n);
  for(int i = 0; i < n; i++) x[i] = in();
  return x;
}

int main(){
  auto a(in<int>(in<int>()))
}

かなり奇妙に感じるコードになりました。 in関数が奇妙に感じるのは当然としても、autoがコンストラクタでも型推論をしてくれるのは意外でした。

vector<int> a = {1, 2, 3};
auto b = a; // <- わかる
auto c(a); // <- !?

冷静になって考えてみると、奇妙の原因は何をするのかわからないin関数が入れ子になっていることのような気がします。

議論

今のままではできることが減ったintでしかありません。メンバ関数を増やして機能を補いましょう。
結局各型ごとに、例えば Int, Double, String クラス等を作る羽目になりますが、BaseTypeみたいなクラスを作って継承すれば手間は少なくなります。

本当はある部分に変数名を書くだけで入力までしてくれる、というものを考えていたんですが、思いつかないのでやめました。

あとC++編とありますが別の編はないです。
もしかすると言語によってそういうのできるのかなぁ……

結論

普通に書いて。

AOJ 0110 Alphametic

覆面算 | Aizu Online Judge

概要

A + B = C
という形式で式が与えられる。式の長さは 126 以下である。
与えられる数値にはひとつ以上の X が含まれている。

X0 以上 9 以下の整数である。
X に当てはまる整数を求めよ。当てはまる整数がない場合は NA を出力せよ。

実装

X に当てはまる数値を全探索する。
多倍長整数でなければオーバーフローする。

C++には多倍長整数はない。

ではどうするか。

modを使うのである。

この嘘解法を落とすケースはあるようで、 mod 10^9 + 7 と mod 10^9 + 9 ではWA。
よくわからない大きな素数でmodを取るとACする

#include<bits/stdc++.h>
#define range(i,a,b) for(int i = (a); i < (b); i++)
#define rep(i,b) for(int i = 0; i < (b); i++)
#define all(a) (a).begin(), (a).end()
#define show(x)  cerr << #x << " = " << (x) << endl;
//const int INF = 1e8;
using namespace std;
const long long M = 67280421310721LL;

vector<string> split(string in, char sp = ' '){
	vector<string> ret;
	stringstream ss(in);
	string s;
	while(getline(ss, s, sp)){
		ret.emplace_back(s);
	}
	return ret;
}

void modmod(vector<string> sp, int start){
	range(i,start,10){
		vector<long long> a(3,0);
		rep(j,3){
			for(auto c : sp[j]){
				(a[j] *= 10) %= M;
				if(c == 'X') a[j] += i;
				else a[j] += c - '0';
			}
		}
		if((a[0] + a[1]) % M == a[2] % M){
			cout << i << endl;
			return;
		}
	}
	cout << "NA" << endl;
	return;
}

int main(){
	string s;
	while(cin >> s){
		rep(i,s.size()) if(s[i] == '+') s[i] = '=';
		vector<string> sp = split(s, '=');

		int start = 0;
		for(auto& i : sp) if(i.front() == 'X' and i.size() > 1) start = 1;
		modmod(sp, start);
	}
}

Firebaseをandroidアプリに追加したときにつまずいたポイント

androidアプリにFirebaseを追加する

これは、Firebaseコンソールから行う。

名前や鍵を設定し、google-services.jsonをダウンロードし、所定の位置に置く。
その後、gradleファイルを変更する。

app_name/app/src/build.gradleを以下のように変更。

dependencies {
  ...
  compile 'com.google.firebase:firebase-core:11.8.0'
  ..
}
apply plugin: 'com.google.gms.google-services'

app_name/build.gradleを以下のように変更。

buildscript {
  ...
  dependencies {
    ...
    classpath 'com.google.gms:google-services:3.2.0'
  }
}

次に、画面上側のオレンジのバーのSyncをクリックする。
しかし、エラー。

Failed to resolve: com.google.firebase:firebase-core:9.0.0

解決策

app_name/build.gradleを以下のように変更。

allprojects {
    repositories {
        jcenter()
        maven {
            url "https://maven.google.com"
        }
    }
}

File google-services.json is missing. The Google Services Plugin cannot function

解決策

google-services.jsonは、app_name直下ではなく、app_name/appに置く。

しかし、エラー。

No matching client found for package name '〇〇'

解決策

app_name/app/google-services.jsonの以下の部分を変更。

"client": [
{
  "client_info": {
    "mobilesdk_app_id": "9:99999999:android:9ccdbb6c1ae659b8",
    "android_client_info": {
      "package_name": " ここを一致させる "
    }
  }
}

com.exampleになっていたので、正しいものに変更する。

コップ本でScala入門 - 2 配列、リストなど

配列

関数型なのに配列を!?

string a[3];
a[0] = "ab";
a[1] = "cd";
a[2] = "ef\n";
for(int i = 0; i < 3; i++){
    cout << a[i];
}
val a = new Array[String](3)
a(0) = "ab"
a(1) = "cd"
a(2) = "ef\n"
for(i <- 0 to 2){
    print(a(i))
}

生成するインスタンスの構成を設定する事をパラメーター化という。
上記の例では、Stringという型パラメーター、3という値パラメーターを設定している。

for式にある to はメソッドである。
詳しく書くと、こうなる。

for(i <- (0).to(2))

数値はIntオブジェクトである。
toというメソッドを呼び出し、Intオブジェクトである2を渡している。
もっというと、すべての演算がメソッド呼び出しである。

val num = Array(1,2,3)

このような初期化もできる。

リスト

配列は変更可能(ミュータブル)であるが、
Scalaのリストは変更不能(イミュータブル)である。
※可変リストもある

val a = List(1,2)
val b = 0 :: a
val c = b ::: a
println(b)
println(c)
出力
List(0, 1, 2)
List(0, 1, 2, 1, 2)

セミコロンで整数をくっつけたり、リストをくっつけたりできる。
Listメソッドにはいろいろある。

その中でも関数言語感を感じるmapの紹介を。

val list = List(1,2,3,4)
println(list.map(a => a * a))
出力
List(1, 4, 9, 16)

リストの各要素に関数を適用する。

タプル

イミュータブルなコンテナオブジェクト。
異なる型の要素を持つ事ができる。

val pair = (1, "a")
val tuple = (1, "a", 3.1)
println(pair._1)
println(tuple._3)
println(tuple)
出力
1
3.1
(1,a,3.1)

ここで、tupleの型はTuple3[Int, String, Double]になっている。

0-indexではないが、これは静的に型付けされたタプルは1から始まるという伝統のためである。

scala> val t = (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22)                                             
t: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) = (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22)

要素をたくさん増やしたくなるが、23個以上はエラーが返ってくる。

集合とマップ

Scalaにはミュータブルなコレクションとイミュータブルのコレクションが区別されている。

イミュータブルなset

var set = Set(1,2,3)
set += 4
println(set.contains(4))
出力
true

setに要素を追加するには+演算子を使う。

イミュータブルなmap

val map = Map(1 -> "a", 2 -> "b", 3 -> "c")
println(map(2))
出力
b

イミュータブルなmapに要素を追加しようとするとエラーが返る。
追加したい場合は、ミュータブルなmapを使う。

test.scala:3: error: value += is not a member of scala.collection.immutable.Map[Int,String]               
Expression does not convert to assignment because receiver is not assignable.                                       
map += (4 -> "a")

Scalaプログラマーに求められる態度

val、イミュータブルオブジェクト、副作用のないメソッドを優先する。
理由があるなら、var、ミュータブルオブジェクト、副作用のあるメソッドを使う。

Haskellは後者を許さない(はず)。一度Haskellに挑戦した事があるが、簡単なコードを書くのにもかなり苦労した。
その点Scalaは融通が利いて良いが、常にJavaとして書いてしまうと関数型言語の考えが身につかないので、うまく使い分ける必要がありそう。

まとめ

  • 配列が使える
  • コレクションはイミュータブルとミュータブルが区別される
  • val、var、イミュータブル、ミュータブルは使い分ける


コップ本でScala入門 - 1 Scalaとは / if、for - noyのブログ
次 ないです