関数ポインタについて

これと言って語れるようなことがなかったので、専門の時に習った関数ポインタについて話そうと思います。

 

C言語での話になりますが、他の言語でも応用できたりするのかなと少し考えてみたりしています。

 

*そもそも関数ポインタとは

関数をアドレスで持って変数にしまってしまおう、というもの。

そのままですね。 



// プロトタイプ宣言
void hoge(void);

int main() {
    void (*p)() = hoge;
    p();
    return 0;
}

void hoge() {
    printf("hoge 呼ばれた。");
}

久々にCを触ったせいで何度もセミコロンを忘れてコンパイラーにとても怒られました

つまり、変数にぶちこめるということは、配列にぶちこむこともできるということ。



// プロトタイプ宣言
void hoge1(void);
void hoge2(void);

typedef void (*p)();
p piyo[] = {hoge1, hoge2};

int main() {
        piyo[0]();
        piyo[1]();
        return 0;
}

void hoge1() {
        printf("hoge1 呼ばれた。\n");
}
void hoge2() {
        printf("hoge2 呼ばれた。\n");
}

わざわざtypedefする必要もなかったような…気もしますが…

今は頭が回ってないのでとりあえずはこれで…

 

配列に入れて何の利点があるんだという話ですね。

switch文で呼ぶメソッドが変わる、なんていう時に使えば、switchより若干早く呼べます。

思い浮かぶ利点はこれくらいでしょうか…

 

ポインタを使う言語をあまり知らないなんとも言えませんが、どこかで応用できたらいいなと思います。

CakePHP3のクエリービルダーについて

PHPフレームワークとして有名なCakephpの3で使える処理速度改善方法の中で最近知ったクエリービルダーについて一つお話しします

クエリーオブジェクトのforeach処理

CakePHP3でクエリービルダーを使用してクエリーオブジェクトの形でDBからデータを取得します。

その際の取得形式で処理時間に差を作ることができます。

例としてArtivlesテーブルからレコードを全件取得するソースを2パターン書いてみる。

パターン1

$articles = $this->Articles->find();
foreach ($articles as $article) {} // 処理実行1

パターン2

$articles = $this->Articles->find()->toArray();
foreach ($articles as $article) {} // 処理実行1

今回は実行時間の差を見やすくするためレコードを1000件用意してみた。

レコード取得の実行時間は以下の通り

パターン1 0.0885570049秒

パターン2 0.0890669823秒

対して違いは見れない。

 

続いて下記のソースをforeachの数を1から10にして実行してみる

foreach ($articles as $article) {} // 処理実行1

foreach ($articles as $article) {} // 処理実行2

foreach ($articles as $article) {} // 処理実行3

foreach ($articles as $article) {} // 処理実行4

foreach ($articles as $article) {} // 処理実行5

foreach ($articles as $article) {} // 処理実行6

foreach ($articles as $article) {} // 処理実行7

foreach ($articles as $article) {} // 処理実行8

foreach ($articles as $article) {} // 処理実行9

foreach ($articles as $article) {} // 処理実行10

レコード取得の実行時間は以下の通り

パターン1 0.1360001564秒

パターン2 0.0915861130秒

0.04秒の違いが見れた。

 

なぜ違いが出たかというとパターン1

$this->Articles->find();

上記時点ではまだSQL文が流れておらずクエリー形式で取得しforeachに入るとイテレートされ実行される

パターン2では

$articles = $this->Articles->find()->toArray();

上記時点でSQL文が流れてクエリーオブジェクトの形式で取得しforeachにはその取得したクエリーオブジェクトで実行している。

パターン2は最初に取得したものをforeachを実行しているのに対してパターン1はforeachのたびにイテレートしているため時間がかかるみたい。

今回は1000件で行いましたが件数が増えれば増えるほどイテレートに時間がかかりますので目に見えて遅くなります。

たとえforeachが2つしかなくとも数万~数十万件のデータを扱った場合はtoArrayを使った方が断然早いです(私はDBデータから複数CSV出力する際に確認しました)

必ずしもクエリーオブジェクトからとるべきとは言えないが、一度取得したデータをforeachで何回かに分け処理を行う場合は使ってみてはどうでしょう。

 

 

 

AdventCalendar投稿方法

  1. ブログのヘッダからログインを選択してログインします

f:id:withoneAdventCalendar:20171205121356p:plain:w500

2.パスワードはメールで送信したものを指定してください

f:id:withoneAdventCalendar:20171205121351p:plain:w500

3.ブログのヘッダが下記のような感じになるので、ここから「記事を書く」を選択します

f:id:withoneAdventCalendar:20171205121348p:plain:w500

4.記事を書いて、左下の「公開する」ボタンを押します。ボタンの右側の矢印を押すと下書き保存も選択することができます

f:id:withoneAdventCalendar:20171205121346p:plain:w500

5.投稿したらブログのヘッダから「記事の管理」を選択します

f:id:withoneAdventCalendar:20171205121343p:plain:w500

6.書いた記事の一番右側のアイコンを押すと書いた記事が開きますので、そのURLをコピーします

f:id:withoneAdventCalendar:20171205121340p:plain:w500

7.Adventarの画面で投稿を予定していた日付の右上の □ を押すと下記のような吹き出しが出ますので、こちらの下の段に記事のリンクをペーストし、「保存」ボタンを押したら完了です!

f:id:withoneAdventCalendar:20171205121326p:plain:w500

heroku + node.jsでSkype bot作った

WithOne Advent Calendar 2017 の 1日目です
私の所属しているグループの本社組は
水曜日にお昼ご飯をみんなで食べに行っています。(通称ランチミーティング)

毎回たくさんの人が参加するのでグループ分けをしているのですが

  • お昼までに各々エクセルに出欠を書く
  • 心優しい誰かが班分けサービスに名前を入力する
  • それをSkypeで発表

というフローがめんどくさいなあと思ったのでSkype bot作ってみました。

Skype Web SDK API reference

最近はSlack botが流行っていますが弊社のグループはSkype派です。
実装するにあたってここの記事を参考にさせていただきました。

Microsoft Bot FrameworkとHerokuとNode.jsを使ってSkype用Botを作る。 - Qiita

とりあえず作ってみた

この中で出てくる
botbuilderというのがMS製のbot作成フレームワーク
restifyというのがREST Web APIを作成するのに便利なフレームワーク
です。

記事を参考にしつつ、とりあえずbotを用意してみたらbotをグループに追加できず詰まる。。

なんとなく動いた・・・で終わらないためのMicrosoft Bot Framework ~ BotからSkypeグループにプロアクティブメッセージを送る ~ - Qiita

グループに参加させるためにはこの記事にあるようにグループに追加するための設定が必要でした。
これは見落としがちな気がするので注意です。

出欠席のデータの保存は、
DBを準備するほどではないなと思ったので、ファイルにガリガリユーザーを書き込むことにしました。
node.jsの「fs」と言うデフォルトの機能を利用するとファイルの操作も簡単にかけます。

出来上がったのがこのような感じ!
f:id:withoneAdventCalendar:20171201021941p:plain

Heroku簡単すぎてやばい

herokuは無料版だからだと思うのですがsshでサーバに入ると結構もっさりでした。
(レスポンスも遅め。。?)

Macのターミナルからだと恐ろしく簡単に導入できるので、
暇つぶしに何か作りたい方に本当にオススメです。
node.jsの環境の設定も、ボタン一つでWeb上からサクッとできます。

何も知らなくてできてしまうのは良いのか。という意見はあると思います。
業務ではもちろん正しい知識を身につけたほうが良いですが、
プライベートではサーバ構築などはかなり時間を取りますしハードルが高いので、
このようなサービスを使って簡単に作れるのは良いのではないかなと思いました。

コード公開しています

コードを公開しています。
フローが面倒云々と言いましたが正直このAdventCalendarのネタの為に作ったものなので
今日動かしてスクショを撮ることを目的としており、未完成です。
(グループを分割する時に4人以上、且ついい感じの人数でないと落ちます。)
完成させて実際に使えるよう頑張ります。。

あとリファクタリング・機能追加のプルリクどなたからでもお待ちしております。
github.com

SwiftとOptionalについて

WithOne AdventCalendar 25日目(http://qiita.com/advent-calendar/2016/withone) 最終日です。

みなさん参加してくださってありがとうございました!
投稿先をQiitaにしたのは少しハードルが高かったかなと思いつつ、
来年もAdventarあたりでまたやりたいなあなんて思っています。


最終日はSwiftとOptionalのススメです。
最近流行りのNull安全な言語。
SwiftもNull安全な言語の一つです。

Null安全な言語といえば、
Python、Kotlin、TypeScriptなどは名前を聞いたことがある人もいるのではないでしょうか。
最近こんな記事も話題になりました。
null安全でない言語は、もはやレガシー言語だ - Qiita

Optionalを通じてSwiftの楽しさ、便利さについて、みなさんに伝わると良いなと思います。

※Swiftではnullをnilと言います


SwiftではOptionalと言う型が使えます。
Optionalとは、「nilを入れることのできる入れ物」を表します。

Swiftではnilを入れることのできる変数かどうかを
あらかじめ設定しないと、変数を作ることができません。

Javaの場合は以下のように書いた場合、
変数hogeにはいつかnullが入る可能性があります。
hogeを使うときには、常にnullの存在を考えなければならないです。

String hoge = "ほげ";  

Swiftの場合、nilを入れることのできる変数かどうかを、
あらかじめ指定しておく必要があります。
書き方は以下の通りです。

// nilを入れることができる変数
var hoge: String? = nil

// nilを代入することができない変数
var hoge: String  = "ほげ"

上下の構文の違いは、型宣言をしているStringの後ろに?がついているかいないかです。
Swiftでは?をつけることで、「この変数はnilを代入することが可能な変数ですよ」
ということを表しています。

ここでは詳しく説明しませんが、
OptionalはOptional<T>という一つの型です。
SwiftではこのOptional<T>を、?を使って簡単に書くことができるようになっています。

非Optional

?のついていないStringには、
nilを代入することができません。
この?が付いていない型を、非Optionalと言います。
非Optionalで宣言した変数にnilを代入しようとすると、
コンパイラがエラーにしてしまうのです。

もしnilになる可能性のある値を代入しようとする場合、
以下のようにデフォルトの値で初期化する書き方をすることができます。
これが結構便利です。

var hoge: String? = nil
var foo: String = "ふー"

// nilの入っている可能性のある変数を代入しようとするとき
// ?? をつけるとデフォルト値を指定できる
foo = hoge ?? "デフォルト"


このように非Optionalの値は、コーディング時にnilが入るかどうか、
他のメソッド中身等を確認したり、nilチェックをする必要がなくなるのです。

Optional

Optionalの型の場合は、値が入っているのか、nilなのかを確認する必要があります。
値が入っていることを確認し、
Optional型から中身を取り出すことをunwrap(アンラップ)と言います。

そもそもStringとString?は
StringとOptional<String>という異なる型になります。
このOptional<String>に入っているStringを使用するためには、
Stringの値をOptionalから取り出してから使用する必要があるのです。

Optionalからの値の取り出し方を以下に記載します。

var hoge: String? = XXXXX // nilかそれ以外かの何かが入っている

// hogeの中身をunwrapHogeに取り出してから使用する
if let unwrapHoge = hoge {
    print(unwrapHoge)
}

Swiftではこのif let 変数名 = Optional型の何か という書き方をよくします。
※let とはSwiftの定数の宣言を表します。varは変数の宣言です。

hogenilではない場合、String?型のhogeから中身が取り出され、
unwrapHogeに代入されます。
hogeの中身がnilだった場合は、falseとなり、このif文の中の処理は行われません。

また、hogeの中身がnilだった場合は、この後の処理を全て行わずにreturnしたいという時もあります。
そんな時はguard文を使用します。

var hoge: String? = XXXXX // nilかそれ以外かの何かが入っている

// hogeの中身をunwrapHogeに取り出して、nilだった場合は以降の処理を行わない
guard let unwrapHoge = hoge else {
    print(unwrapHoge)
    return
}

// その後の処理色々
print(unwrapHoge)


guard文は、
「設定した条件式に当てはまる場合のみ、
それ以降の処理を実行する」
ということを表す構文になります。

guard文の中では必ず、returnやbreakなど、
以降の処理を行わない旨の処理を記述する必要があります。

このようにして、Optionalの変数は、
値が入っている場合のみ使用されるよう作られているのです。

※中身がnilでも使用する方法はありますが
今日はここまで。。

最後

Optionalの使い方について少しだけ興味が湧いてきましたか・・?
nilの扱い方について少しだけ便利になるOptionalですが、
nilに全くならないというわけではありません。

Optionalの型をnilが入っていても使うことはできてしまいますし、
デフォルトの値を設定する例を出しましたが、
あの処理自体もきちんと考えてデフォルトを設定しなければ、
ただエラーの握りつぶしを行うことと同じことにもなるのです。

最後に、

Swiftはいいぞ!