サンプション・アーキテクチャをC++で実装
サンプション・アーキテクチャとは
ロボットの制御などに用いられ、それぞれのモジュールの階層構造を管理するアーキテクチャです。
ある目標に向かって行動するために最も重要なモジュールが下層にあり、上位層になればなるほどより抽象的なモジュールが構成される形が一般的ですね。
自動運転で例えると、道順通り運転する最上位層もモジュールがあって、下層モジュールには、渋滞してたら回避するモジュールや、車が突っ込んで来たら回避するモジュール…というような構成です。
実際に私の研究のラジコンカーにも実装されております。
日本語wikipediaより英語のほうが詳しい説明があります。
ja.wikipedia.org en.wikipedia.org
また、今回の実装は以下のサイトにあるjavaのソースをc++に翻訳しました。 www.ibm.com
実装クラス
大きくわけて3つあります。 1. Behavior(基底クラス) 2. BehaviorBasedAgent(実行クラス) 3. main
注意点 - これから説明するソースにはCarというクラスがありますが、車の情報を管理するクラスだと思ってください(アクチュエータとかのアクセスもここから) - すべてヘッダオンリークラスです - 元々ソースにあったコメントは英語、処理の代わりとして日本語のコメント入れてます
ファイル構成
. ├── main.cpp ├── Car.h ├── BehaviorBasedAgent.h ├── subsumption │ ├── Behavior.h │ ├── Drive.h │ └── Stop.h
- Drive.h コース通り運転するモジュール
- Stop.h 停止処理があるモジュール
として説明していきます。
Behavior 基底クラス
Behavior.h
#pragma once #include "../Car.h" // Must add "override" modifier ! class Behavior { protected: Car& car; public: // This constructor is supposed to be called from child class Behavior(Car& car_) : car(car_){}; // virtual function virtual bool isActive() { throw std::runtime_error("Called base class @ Behavior.h isActive()"); return false; } virtual void act() { throw std::runtime_error("Called base class @ Behavior.h act()"); } };
実装はかんたんでisActive()
にmoduleがactiveになる条件を記述して、act()
に行動を記述します。
Behavior実装例(Stopクラス)
Stop.h
#pragma once #include "../Car.h" #include "Behavior.h" class Stop : public Behavior { public: Stop(Car& car_) : Behavior(car_){} bool isActive() override { // ストップする条件を満たしたら(信号、コースアウト…) return true; } void act() override { // Carクラスを使って停止処理 } };
BehaviorBasedAgent クラス
BehaviorBasedAgent.h
#pragma once #include "subsumption/Behavior.h" #include "subsumption/Stop.h" // - RelationMat // BehaviorRelationMat[i][j] : 行動優先度がi<jならば[i][j]=false using BehaviorRelationMat = std::vector<std::vector<bool>>; using Behaviors = std::vector<std::unique_ptr<Behavior>>; class BehaviorBasedAgent { private: Behaviors& behaviors; BehaviorRelationMat suppresses; int current_behavior_index; public: BehaviorBasedAgent(Behaviors& behaviors_, BehaviorRelationMat suppresses_) : behaviors(behaviors_), suppresses(suppresses_), current_behavior_index(0) {} void step() { std::vector<bool> is_active(behaviors.size()); for (size_t i = 0; i < behaviors.size(); i++) { is_active[i] = behaviors[i]->isActive(); } bool ran_behavior = false; size_t counter = 0; while (!ran_behavior) { bool run_current_behavior = is_active[current_behavior_index]; if (run_current_behavior) { for (size_t i = 0; i < suppresses[0].size(); i++) { if (is_active[i] && suppresses[i][current_behavior_index]) { run_current_behavior = false; break; } } } if (run_current_behavior) { if (current_behavior_index < static_cast<int>(behaviors.size())) { // do action behaviors[current_behavior_index]->act(); } ran_behavior = true; } if (behaviors.size() > 0) { current_behavior_index = (current_behavior_index + 1) % behaviors.size(); counter++; if(counter == behaviors.size()) break; } } } };
main.cpp(インスタンスを持つ)
#include "BehaviorBasedAgent.h" int main(int argc, const char** argv) { //他の処理 ... // This instance deals with modules that act as actuators Behaviors actuator_module; actuator_module.push_back(std::unique_ptr<Behavior>(new Stop(car))); actuator_module.push_back(std::unique_ptr<Behavior>(new Drive(car))); BehaviorBasedAgent actuator_agent(actuator_module, {{false, true}, {false, false}}); // control loop while(1){ subsumption.step(); } ... //他の処理 ... return EXIT_SUCCESS; }
- BehaviorBasedAgentに他のファイルをincludeしてるので、mainではこのファイルだけで大丈夫です
- あとは制御処理のループでstep()を呼んで上げれば勝手に動作します
-
actuator_agent
を初期化するときに、関係の行列を一緒に定義します
ibmのサイトに詳しい説明があるのですが、それぞれモジュールの関係性を、行動優先度がi<jならば[i][j]=falseと定義します。
なのでこの行列の対角成分は自身との比較なのでfalse
ですね。
もしすべてのモジュールの関係性が、下層モジュール < 上層モジュルならば、下false
の三角行列になります。
c++でpimplイディオムの書き方
はじめに
私は基本的にヘッダオンリーでC++のソースを書くタイプなのですが、研究で使うRCカーの制御プログラムが肥大化してきて、フルビルドに10分近くかかるようになってしまいました。そのまま実装とヘッダに分けても良いのですが、どうせならと思ってPimplイディオムを導入しました。
以下の記事を参考にさせて頂きました。 qiita.com
メリット・デメリット
Pimpl とは “Pointer to Implementation"から来ているみたいですね。
メリット
- private なものを隠すことができる
- コンパイル時間が短くなる
デメリット
- ソースが肥大化する
- 無駄にメモリ確保が必要
アンチパターンなんて記事も見るので、良い悪いは人それぞれだとは思いますが、個人的にprivateなものがヘッダからは見えず、ソースが読みやすくなることと、privateな部分での変更をいちいちヘッダにも反映させなくて良いのが気に入ってます。
使い方
ヘッダオンリー例
手順どおりにやれば至ってシンプルです。
まず、以下のようなソースを例に説明します。
test.h
#ifndef TEST_H_ #define TEST_H_ #include <iostream> class Test { private: int pri_value; void twice() { pri_value *= 2; } void print() { std::cout << "pri_value: " << pri_value << std::endl; } public: int pub_value; Test() : pri_value(2), pub_value(4) { std::cout << "constructor" << std::endl; } ~Test() { std::cout << "destructor" << std::endl; } void process() { twice(); print(); } int process2(const int v_) { return pub_value * v_; } }; #endif // TEST_H_
main.cpp
#include "test.h" int main(void){ Test test; test.process(); std::cout << "result of process2: " << test.process2(2) << std::endl; test.pub_value = 100; std::cout << "result of process2: " << test.process2(4) << std::endl; }
実行例
$ ./a.out constructor pri_value: 4 result of process2: 8 result of process2: 400 destructor
手順
test.h
のprivateにTestImpl(クラス名+Impl)の前方宣言と、そのクラスへのポインター(pimpl)を設置test.cpp
を作成し、TestImplクラスを宣言test.h
のprivate, publicの中身(変数、関数、コンストラクタ…)を新しいクラスに移動- Testクラスのpublic変数を参照に変更
test.cpp
の、TestクラスコンストラクタでTestImplをnewして、参照で定義したpublic変数をpimplの保持する実体へ繋ぐtest.cpp
にTestクラスのpublic関数の実装をpimplの関数の実体へと繋ぐ
書き換え後
test.h
#ifndef TEST_H_ #define TEST_H_ #include <iostream> #include <memory> #include <vector> class Test { private: class TestImpl; std::unique_ptr<TestImpl> pimpl; public: int& pub_value; Test(); ~Test(); void process(); int process2(const int); }; #endif // TEST_H_
test.cpp
#include "test.h" class Test::TestImpl { private: int pri_value; void twice() { pri_value *= 2; } void print() { std::cout << "pri_value: " << pri_value << std::endl; } public: int pub_value; TestImpl() : pri_value(2), pub_value(4) { std::cout << "constructor" << std::endl; } ~TestImpl() { std::cout << "destructor" << std::endl; } void process() { twice(); print(); } int process2(const int v_) { return pub_value * v_; } }; Test::Test() : pimpl(new TestImpl()), pub_value(pimpl->pub_value) {} Test::~Test() {} void Test::process() { pimpl->process(); } int Test::process2(const int v_) { return pimpl->process2(v_); }
main.cpp
は同じ
実行例
$ ./a.out constructor pri_value: 4 result of process2: 8 result of process2: 400 destructor
コメント
- unique_ptrにすることでポインタ管理の心配いらず
- 関数を一度無駄に経由することになるので、コピーコストラクタ走るのが嫌な時は転送すれば良い(コピーよりはまし)
まとめ
確かにソースは肥大化しますが、こっちのほうが1つのファイルで何やってるかわかるので、読みやすいような気がします。
1からFirebase Hosting + Basic認証のdeployをGithub Actionsで自動化する
はじめに
参考にさせた頂いた記事 qiita.com qiita.com
手動deployまで
まず最初の記事を参考にFirebaseで新規プロジェクトを作成します。
基本的に手順に従っていれば問題ないです。
ちなみに注意点として、
公開したいフォルダをfunctions以下にしないとうまくできませんでした。(正しいやり方があるとはおもうのですが…)
[本題] Github Actionsでdeploy
.github/workflows/nodejs.yml
を追加する部分ですが、私はこの記事通りコピペしてもPermissionで怒られて動作しませんでした。(2020/04/01現在)
私はnode.jsのbuildは不要ですので、 npm install 解決方法 を参考にしながら、以下のように.ymlファイルを作成しました。
name: Node CI on: push: branches: - master jobs: deploy_to_firebase_hosting: runs-on: ubuntu-latest strategy: matrix: node-version: [12.x] steps: - name: Checkout the repository uses: actions/checkout@master - name: Deploy to Firebase run: | mkdir ~/.npm-global npm config set prefix '~/.npm-global' export PATH="$HOME/.npm-global/bin:$PATH" npm install -g npm npm install -g firebase-tools cd functions npm install --save express npm install --save basic-auth-connect cd .. firebase deploy --token $FIREBASE_TOKEN env: FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
あとは、記事通りFIREBASE_TOKENだけGithubの環境変数に追加したら準備完了です。
(今回は公開するだけなので、PASSWORDは不要)
masterにpushすると自動deployが走り、勝手に公開されるようになっています。
CIの注意点
この.ymlを書いていてハマったのが、各stepのrunの環境変数などは引き継がれないらしく、exportしても、.bashrc
に追記しても別のrunで反映されなかったため、runを一つにまとめました。
もしbuildをするなら、その点注意が必要です。(各runの最初でpathを設定など)
最後に
もしFirebase functionなどを使わないで、シンプルにdeployする時なんかは以下のリポジトリを使うと便利かもしれません。
就活のためにポートフォリオを作る
はじめに
ポートフォリオ作成に時間をかけすぎたら本末転倒なので、サクッとテンプレートを探す(ライセンスをよく確認しましょう)
startbootstrap.com
などが王道でしょうか
ふつうに bootstrap portfolio templateとかで検索すると様々ヒットします
ライセンスについて
私が使用したテンプレートはMITライセンスでした
以下の記事によれば、公開したソースコード内にMITライセンスの記述を行えば良いとのこと 公開ライセンスの話 - Qiita
改変
テンプレートそのままだと面白くないので、+α追加していきます
はてなブログカードのembed
はてなブログで使用されている埋め込み型のカードを使いたいときには以下ソースコードの url hereの部分に埋め込みたいURLを入れるだけで実現できます。
<iframe style="width:100%;height:190px;max-width:680px;" title="%title%" src="url here" frameborder="0" scrolling="no"> <a href="%url%">%title%</a> </iframe>
スキルセットのレーティング
www.cssscript.com 私はこれにプラスでとFont-Awesome iconとタイトルをつけました。
… <div class="contentContainer"> <h3 class=mr-3><i class="card-title fas fa-code mr-3"></i>スキル</h3> …
イメージギャラリー
人柄をみるような会社では、趣味などを聞いて来る場合があると聞いたので、最後のページに自分の趣味である写真のギャラリーをのせました。
参考にしたギャラリーのベースは以下です
startbootstrap.com
そしてこの画像をクリックしたときに拡大するように、lightboxを導入しました。
導入方法から使い方まで本家ページにあります。
lokeshdhakar.com
ギャラリーのaタグの部分に必要項目追加します。
<a href="img/bike1.jpg" data-lightbox="pic" class="d-block mb-4 h-100"> <img class="img-fluid img-thumbnail" src="img/bike1.jpg" alt=""> </a>
これで、クリック時の動作がリッチになりました。
お役立ちリンク
次回
次はこれをFirebase Hostingを使ってデプロイしたいと思います。
また、せっかくなのでGitHub Actionsを使って、デプロイの自動化もやってみようと思ってます。
追記
記事公開しました! tmyoda.hatenablog.com
RaspberryPiで自宅にVPNを構築したときの備忘録
参考にさせて頂いた記事
サーバ構築
基本的にはこの記事を参考にすれば問題はないのですが,幾つか注意点があるのでそれを補足する形で説明します
準備
- RaspbianはLiteでもDesktopでもどっちでもいいです
- sshログインは画面とキーボードを繋げて作業するなら必要ないです(あると後々便利ですが)
初期設定でipアドレスを固定していますが,ルータがDHCPでIPを振っている場合,最悪被ることがあるので, ルータ側の設定でDHCP設定を変更して固定IPに被らないようにします
OpenVPNのインストール
sudo su
を行ってスーパーユーザーで行うと楽です
build-ca
,./build-key-server
のときに様々入力が求められますが基本的に空欄(そのままEnter)で大丈夫です。ただ,Common Name (eg, your name or your server's hostname) []:
を聞かれたときはなにか任意の名前をつけておきましょう
以下4つは,クライアント側で必要になるのでzipにして保存すると取り回しが楽です
後でscpかなんかで取り出しやすい場所に移しておくと良いと思います
zip vpnclient.zip ca.crt ta.key client.crt client.key
サーバの設定
ここがけっこう鬼門で,この通り設定してもserver.conf
のエラーで動かなかったです。
;
も#
もコメントアウトらしいので注意です。
まず以下のように編集します。
ca /etc/openvpn/ca.crt cert /etc/openvpn/server.crt key /etc/openvpn/server.key dh /etc/openvpn/dh2048.pem tls-auth /etc/openvpn/ta.key
その後,
push "redirect-gateway def1 bypass-dhcp"
をコメントアウトして
以下のDNSを設定しているところをコメントアウトするか,自分の契約しているプロバイダのDNSサーバに変更する。(すると早いってだけで,Public DNSでも動作すると思います)
push "dhcp-option DNS 208.67.222.222"
以下のサイトからDNSサーバを確認できます
プロバイダのDNSサーバーアドレス一覧及び確認する方法 | インターネット接続解説ブログKAGEMARU-info
ちなみに,コメントアウトされていたDNSアドレスはopendns.comから提供されてるアドレスみたい
サーバのスタート
ここまできたらいよいよサーバを立てます。
- リスタート
systemctl restart openvpn
- 自動起動に登録(任意)
systemctl enable openvpn
- ついでにラズパイのポートを開けて,NATを設定 以下コマンドのやっていることは,
- udpパケットのport1194番は通す
- 10.8.0.0/24からのパケットをマスカレード(パケットのソースIPをこのマシンのeth0ように見せかけて転送)する。
/etc/rc.local
に追記すると起動時に毎回設定してくれる(逆にしないと毎回設定する必要がある)
iptables -A INPUT -p udp -m state --state NEW -m udp --dport 1194 -j ACCEPT iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
追記したら再起動
起動確認
以下のコマンドで active(running)になっていればOKです。なっていなければどこでエラーなのか確認します。
systemctl status openvpn@server.service
もしエラーが出ていたら
journalctl -u openvpn@server.service
でエラーの内容を確認します。
ちなみに私はserver.conf
にエラーがある旨のログがあったので,どこでエラーが出てるのか以下のコマンドで詳細を確認しました。
openvpn --config /etc/openvpn/server.conf
クライアント側
クライアント側はあの記事の通りに設定すれば問題ないです。
remoteのxxx.xxx.xxx.xxxはサーバのIPアドレス。
とありますが,これはローカルIPではなくグローバルIPなのでお間違えなく。(あたりまえですが)
おまけ
接続されているクライアントを見る方法
cat /etc/openvpn/openvpn-status.log
JavaとKotlinの比較
Java vs Kotlin
参考にさせて頂いた記事
https://qiita.com/koher/items/bcc58c01c6ff2ece658f
メモ書きで残していたものなのでなぐり書きです
Javaとの違い
- 文末の
;
いらない - asで別名付けられる
import java.sql.Date as SqlDate
変数編
final
な変数はval
- 変更可能な変数は
val s: String = "abc"
- 型推論は
var s = "abc"
と右辺値から判断 - 型宣言に
?
を付けた場合は nullable (Kotlin は明示的に ? を付けないと null を代入できない) - 変数に付けた場合は Safe Call(安全な呼び出し)
aaa?.length
// Java int a = 42; final boolean b = true;
// Kotlin var a: Int = 42 val b: Boolean = true
制御構文
// Java final String foo; if (bar < 42) { foo = "abc"; } else { foo = "xyz"; } // Java final String foo = bar < 42 ? "abc" : "xyz";
// Kotlin val foo = if (bar < 42) { "abc" } else { "xyz" } // Kotlin val foo = if (bar < 42) "abc" else "xyz"
- while 同じ
- c++の拡張forと同じ
// Java for (int number : numbers) { System.out.println(number); } // Java for (int i = 0; i< 100; i++) { System.out.println(i); }
// Kotlin for (number in numbers) { println(number) } // Kotlin for (i in 0 until 100) { println(i) } // Kotlin for (i in 99 downTo 0) println(i) // for (int i = 99; i >= 0; i--) for (i in 0 until 100 step 2) println(i) // for (int i = 0; i < 100; i += 2) for (i in 1..100) println(i) // for (int i = 1; i <= 100; i++)
switch(){}
->when(){}
- newは不要
class
- kotlinはデフォルトがpublic
- kotlinはclassのフィールドがなく,getter/setterが存在しない
- その代わりプロパティと呼ばれるものがある
コンストラクタ
// Kotlin class Person(val firstName: String, val lastName: String) { var age: Int init { age = 0 } ... }
// Java public class Person { private final String firstName; private final String lastName; private int age; public Person(String firstName, String lastName, int age) { this.firstName = firstName; this.lastName = lastName; this.age = age; } public Person(String firstName, String lastName) { this(firstName, lastName, 0); } ... }
// Kotlin class Person(val firstName: String, val lastName: String, var age: Int) { constructor(firstName: String, lastName: String) : this(firstName, lastName, 0) { } ... }
プロパティ?
// Java final int age = person.getAge(); person.setAge(age + 1); // Java public class Person { ... public String getFullName() { return firstName + " " + lastName; } }
// Kotlin val age = person.age person.age = age + 1 // Kotlin class Person { ... val fullName: String get() { return firstName + " " + lastName } }
式が一つで済むときはこれで住む
// Kotlin val fullName: String get() = firstName + " " + lastName
メソッド
- 特に変化は無く
fun
が必要なだけ - fun 関数名(引数):戻り値
// Kotlin class Person(val firstName: String, val lastName: String) { ... // 時間経過を表すメソッド fun elapse(years: Int): Int { age += years return age } }
- 式が一つで済むなら以下のようにかける
// Kotlin fun getFullName(): String = firstName + " " + lastName
カスタムgetter/setter
- 基本的にgetter/setterは必要ないが,何か処理したい時
// カスタムゲッターを定義 val nameLength: Int get(): Int { return this.name.length } // カスタムセッターを定義 var name: String = "" set(value) { println("nameに${value}が設定されました。") // 値は field変数に格納する field = value }
継承
- Kotlin ではデフォルトでクラスやメソッドは final
- final でなくすには open のキーワードをつける
extend
の代わりに:
- override修飾子は必須項目
val
もvar
もついていない -> 何もつけなければそれはただの引数
// Kotlin // `open` で `final` でなくす open class Person(val firstName: String, val lastName: String, var age: Int) { ... open val fullName: String // `final` でなくす get() = firstName + " " + lastName } class EasternPerson(firstName: String, lastName: String, age: Int) : Person(firstName, lastName, age) { override val fullName: String get() = lastName + " " + firstName // 姓 名の順にする }
データクラスとコピー
- データだけ保持したいクラスは
data
修飾子をつける - 以下の要素が自動生成される
- equals()/hashCode()ペア
- "User(name=John, age=42)"って表示するtoString()
- 宣言順で内容を取り出すcomponentN()関数
- copy()
data class User(val name: String, val age: Int)
- fun copyがデータクラスに自動生成される
val jack = User(name = "Jack", age = 1) val olderJack = jack.copy(age = 2) // nameはそのままでageだけ変更したコピーを生成
interface
// Java public interface Foo { int getBar(); void baz(String qux); }
// Kotlin interface Foo { val bar: Int fun baz(qux: String) }
コレクション
// Java final List<Integer> a = Collections.unmodifiableList(Arrays.asList(2, 3, 5)); final List<Integer> b = new ArrayList(); b.add(2); b.add(3); b.add(5);
// Kotlin val a: List<Int> = listOf(2, 3, 5) val b: MutableList<Int> = mutableListOf() b.add(2) // 可変 b.add(3) // 可変 b.add(5) // 可変 // Kotlin val a = mutableListOf(2, 3, 5) val b: List<Int> = a println(b) // [2, 3, 5] a.add(7) println(b) // [2, 3, 5, 7] // Kotlin val a = intArrayOf(2, 3, 5)
deligate(譲位)
https://developer.android.com/training/basics/fragments/communicating.html#kotlin
- 難しいことはよくわからんが,保持されてる側のクラスから,保持してる側のクラスへ通知するしくみ
- playGroundで試せるよ
- 生成される側にListenerインターフェイス定義
- callback変数を定義して,それをsetする関数用意(どこかで生成された関数オブジェクト?を格納)(本系はlateinitじゃなくても動いてた)
- インスタンス保持側でinterfaceの実装(本家はoverrideなかった...)
// インスタンス生成される側に定義 class Fragment(){ internal lateinit var callback: SomeListener fun setSomeListener(callback: SomeListener){ this.callback = callback } fun sendMessage(){ callback.messageRecv("Hello") } // This interface can be implemented by the Activity, parent Fragment, // or a separate test implementation. interface SomeListener{ fun messageRecv(str: String) } } // 実装はインスタンスを持つ側 class Activity(): Fragment.SomeListener{ val fragment = Fragment() //本来onFragmentAttachとか //だから本来この上でいちいちfragment定義せんでもよいのよな //fun onAttachFragment(fragment: Fragment) { // if (fragment is HeadlinesFragment) { // fragment.setOnHeadlineSelectedListener(this) // } //} init { // コンストラクタで渡そう fragment.setSomeListener(this) } override fun messageRecv(str: String){ println("getMessage!: " + str) } } fun main() { val activity = Activity() activity.fragment.sendMessage() }
そんなsetSomeListenerのところコンストラクタで渡せばもっとシンプル!!
lazy
http://atma1333.hatenablog.com/entry/2017/08/02/124122
より
- lazyは引数に関数を取り,この関数は対象のプロパティにセットされる値を返します。
- 対象のプロパティが最初に参照された時lazyの引数に渡された関数が呼び出されます。
- 2回目以降の参照では呼び出されません。
class CustomView(context: Context?) : FrameLayout(context) { var text1: TextView? = null var text2: TextView? = null var image: ImageView? = null init { LayoutInflater.from(context).inflate(R.layout.item_view, this) text1 = findViewById(R.id.text1) text2 = findViewById(R.id.text2) image = findViewById(R.id.image) } }
lazyつかって書くと
class CustomView(context: Context?) : FrameLayout(context) { val text1: TextView by lazy { findViewById<TextView>(R.id.text1) } val text2: TextView by lazy { findViewById<TextView>(R.id.text2) } val image: ImageView by lazy { findViewById<ImageView>(R.id.image) } init { LayoutInflater.from(context).inflate(R.layout.item_view, this) } }
lateinit
- NonNullなプロパティーの初期化をconstructorより後に遅らせられる機能
as
- キャスト 失敗でエラー
- as? はキャストだけど失敗でnullになる
オブジェクト式
- あるクラスの一つだけを修正(オーバーライド)したインスタンスがほしいとき
open class A(x: Int) { public open val y: Int = x } interface B {...} val ab: A = object : A(1), B { override val y = 15 }
ラムダ式
- kotlinは関数が第一級関数だから関数オブジェクトとして扱える
public class Main { fun main(args: Array<String>) { val op = { a:Int, b:Int -> a+b} calc(1,2,op) // 3 } fun calc(a: Int, b: Int, op: (Int, Int) -> Int): Int { return op(a, b) } }
型推論できないときは明示的に
val noReturn : Int -> Unit = { num -> println(num) } val more : (String, Int) -> String = { str, int -> str + int } // クラス拡張としてもラムダ式OK val another : String.(Int) -> String = { this + it }
スコープ関数
val s = "hoge".let { it.toUpperCase() } println(s) //=> HOGE val s = "hoge".run { toUpperCase() } println(s) //=> HOGE val s = "hoge".apply { toUpperCase() } println(s) //=> hoge
let
- 任意の型の拡張関数
- letは引数として関数を受け取り,任意の型で返す
- nullableな変数に対して使うことが多い
val upperCase: String? = foo?.let { it.toUpperCase() } // nullなら?.呼び出しによりletが実行されない // nullじゃないなら,letが実行され大文字で帰ってくる
run
- letとwithが合わさった感じ
- runは任意の型Tの拡張関数でそのTをレシーバとするメソッドのような関数を引数に取る
val frame: JFrame? = frameOrNull() frame?.run { size = Dimension(600, 400) defaultCloseOperation = JFrame.EXIT_ON_CLOSE setVisible(true) }
apply
- letは引数として関数を受け取り,レシーバを返す
val frame: JFrame = JFrame("My App").apply { size = Dimension(600, 400) defaultCloseOperation = JFrame.EXIT_ON_CLOSE setVisible(true) }
class MyFragment: Fragment() { companion object { fun new(foo: Int, bar: Int): MyFragment = MyFragment().apply { arguments = Bundle().apply { putInt("foo", foo) putInt("bar", bar) } } } }
Kotlin : as, !, ? 周りのチートシート
この記事が良くまとまっていて秀逸です http://increment.hatenablog.com/entry/2015/10/31/090743
pandasで行検索するときの速度比較
pandasで行検索
忙しい人向け
結論から言うと,apply
, map
, query
を使うよりも ==
, <=
等の等号不等号を使った検索の方が早いです.
dfを定義
import pandas as pd df = pd.DataFrame({"col1":list(range(500000)), "col2":list(range(500000)), "col3":list(range(500000))}) df.shape # (500000,3) # df中身 col1 col2 col3 0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4 .... 499995 499995 499995 499995 499996 499996 499996 499996 499997 499997 499997 499997 499998 499998 499998 499998 499999 499999 499999 499999
検索条件が1つのとき
apply
df[df['col1'].apply(lambda x: x == 1000)]
Wall time: 160 ms
map
df[df['col1'].map(lambda x: x == 1000)]
Wall time: 159 ms
query
df.query('col1==1000')
Wall time: 33.9 ms
そのまま(名称がわかりません)
df[df['col1'] == 1000]
Wall time: 2.02 ms
圧倒的そのままやる方が早い
検索条件が2つのとき
apply
df[df.apply(lambda x: x['col1'] == 1000 and x['col2'] == 1000, axis=1)]
Wall time: 7.79 s
map
- dfに対してやる方法があれば教えて頂きたいです
query
df.query('col1==1000 & col2==1000')
Wall time: 8.68 ms
そのまま
df[(df['col1'] == 1000) & (df['col2'] == 1000)]
Wall time: 3.44 ms
applyがdfに対してだと急に遅くなった
結局,2つでもそのままやる方が早いらしい
検索条件が3つのとき
apply
df[df.apply(lambda x: x['col1'] == 1000 and x['col2'] == 1000 and x['col3'] == 1000, axis=1)]
Wall time: 8.14 s
query
df.query('col1==1000 & col2==1000 & col3==1000')
Wall time: 9 ms
そのまま
df[(df['col1'] == 1000) & (df['col2'] == 1000)& (df['col3'] == 1000)]
Wall time: 5.03 ms
結局そのままが早い
結論
pandasから行でデータを抽出するときはapply,map,queryは使わなくても平気みたいですね
検索条件を等号から不等号へと変えてみましたが結果は同じでした
Android MVVM
はじめに
qiita.com こちらの記事をベースにMVVMについて学習したので,その備忘録です.
MVVM
フォルダ階層
. ├── service │ ├── model │ │ ├── Project.java │ │ └── User.java │ └── repository │ ├── GithubService.java │ └── ProjectRepository.java ├── view │ └── ui │ └── MainActivity.java └── viewmodel └── ProjectListViewModel.java
model
- UIに関係ない処理を行う場所
- repositoryはviewModelに対するデータプロバイダ(API叩くソースを書くところ)
- viewModelから呼び出され,コルーチン(非同期)でサーバからデータを取得
- [コルーチン]関数呼び出しを途中で中断できるが,スタック領域に残っており,もう一度呼ぶとその中断したところから再開できる
MVVMSamleで使ったkotlin文法
companion
Kotlin では、class 定義の中で object を宣言するとき、companion というキーワードをつけることができる。このキーワードがついた object をコンパニオンオブジェクトと呼ぶ.コンパニオンオブジェクトのメンバは クラス名.メンバ名 でアクセスできる.- つまりjavaのstaticの代わり
- companion object の後ろの {} の中は、通常のクラスの本体と同じように実装
companion object Factory
のように名前付けられるけど,Book.Factory.FREE_PRICEでもBook.FREE_PRICEでもどっちでもアクセス可能- しかも,クラスの中でcompanion objectは1つしかだめだから,名前つける意味ないかもね
companion補足
data class Book(val title: String, val price: Int) { companion object { const val FREE_PRICE = 0 fun newFreeBook(title: String) = Book(title, FREE_PRICE) } } fun main() { val book = Book.newFreeBook("Free Kotlin") println(book) //=> Book(title=Free Kotlin, price=0) }
- Book.xxx() という記述は、実は Book.Companion.xxx() の省略記法 https://qiita.com/satorufujiwara/items/f42b176404287690f1d0
MutableLiveData vs ObservableFiel
両方ともDataBindingに使えるオブジェクト
MutableLiveData<>()
- ActivityやFragmentのライフサイクルに応じて、ほぼ自動で購読管理をしてくれる。
- 意図しないクラッシュ防ぐことができる
- DataBindingできる
ObservableField<>()
- DataBindingをするときに使う。
- ライフサイクルには対応しておらず、購読管理を自動ですることはできない
MutableLiveDataを使いましょう
Application
- viewModelからリソースにアクセスしたりできる
- viewModelProvidersで初期化するにはViewModelかAndroidViewModelを継承する必要がある
- この方法で初期化したViewModelは画面回転時も値を引き継ぐことができる
- ViewModelProviders.of()で渡すものによってViewModelのスコープが決定
- Activityを渡せばそのActivityで使えますし、Fragmentと同じ
- Fragmentで親Activityのインスタンスを渡せばActivity内のスコープとなるため、ActivityとFragmentで同じViewModelを操作することができる
- コールバック付けなくても,データ共有できるみたい
class ProjectViewModel(private val myApplication: Application, private val mProjectID: String) : AndroidViewModel(myApplication)