クラウドエンジニアのノート

情報技術系全般,自分用メモを公開してます。

サンプション・アーキテクチャを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

手順

  1. test.hのprivateにTestImpl(クラス名+Impl)の前方宣言と、そのクラスへのポインター(pimpl)を設置
  2. test.cppを作成し、TestImplクラスを宣言
  3. test.hのprivate, publicの中身(変数、関数、コンストラクタ…)を新しいクラスに移動
  4. Testクラスのpublic変数を参照に変更
  5. test.cpp の、TestクラスコンストラクタでTestImplをnewして、参照で定義したpublic変数をpimplの保持する実体へ繋ぐ
  6. 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する時なんかは以下のリポジトリを使うと便利かもしれません。

github.com

就活のためにポートフォリオを作る

はじめに

ポートフォリオ作成に時間をかけすぎたら本末転倒なので、サクッとテンプレートを探す(ライセンスをよく確認しましょう) 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を構築したときの備忘録

参考にさせて頂いた記事

qiita.com

サーバ構築

基本的にはこの記事を参考にすれば問題はないのですが,幾つか注意点があるのでそれを補足する形で説明します

準備

  • 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

制御構文

  • if 基本的にjavaと同じ
  • ifが式として評価されるため,三項演算子として使える
// 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が存在しない
    • その代わりプロパティと呼ばれるものがある

コンストラク

  • プロパティ(javaで言うfield)の宣言とコンストラクタの宣言
  • このような形をプリマリコンストラクタという
  • プロパティの初期化?宣言?以外の処理をするにはinitが必要
// 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修飾子は必須項目
    • valvarもついていない -> 何もつけなければそれはただの引数
// 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)
}

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) 

このブログについて

はじめまして

2020年4月から大学院に進学ということで,心機一転情報発信していこうかと決意しました.

を中心に発信できればと思います.
続くかわかりませんが,がんばります.