m_shige1979のときどきITブログ

プログラムの勉強をしながら学習したことや経験したことをぼそぼそと書いていきます

Github(変なおっさんの顔でるので気をつけてね)

https://github.com/mshige1979

Rustのhelloworldを試す。

プログラミング言語

Rust
スクリプト言語のような書き方でC++のような高速化ができるらしいよ
詳しくはわからんがとりあえずやってみる

環境

Mac Book Air(もう古いかも…5年以上前のものだし)

インストール

curl https://sh.rustup.rs -sSf | sh

環境設定

source $HOME/.cargo/env

でOK

確認

$ rustc --version
rustc 1.37.0 (eae3437df 2019-08-13)

まずはHelo worldのみ

main.rs
fn main() {
    println!("hello, world");
}
コンパイル
rustc main.rs
./main

hello, world

ついでに超簡単なfizzbuzz

fn main() {
    for num in 1..51 {
        let mut _str = "";
        if num % 3 == 0 && num % 5 != 0{
            _str = "fizz";
        } else if num % 3 != 0 && num % 5 == 0 {
            _str = "buzz";
        } else if num % 3 == 0 && num % 5 == 0{
            _str = "fizzbuzz"
        }

        println!("{}:{}", num, _str);
    }
}

所感

まだ、触ったばかりでわからない状況
メモリ管理もいろいろできるみたいだし、文法の学習をしながら他の言語との比較を行っていく

javascriptのPromiseとasync / awaitについて少し試す

Promiseは

並列処理でちょっと前に学習したやつで

function sampleTask1() {
    return new Promise(function(resolve, reject) {
        setTimeout(function () {
            console.log('sample1');
            resolve("sample1");
        }, 3000);
    });
}

って定義したら

sampleTask1()
    .then(function(result) {
        console.log("result", result);
    })
    .catch(function(error) {
        console.log("error");
    });

で実行した際に非同期で動作して、正常時にはresolve、異常時にはrejectで返却するやつです。

今回は?

async / awaitがある
これは
非同期処理をもう少しスッキリ書けるらしい

まずは今までのやつ

console.log("start");
Promise.resolve()
    .then(function() {
        return new Promise(function(resolve, reject) {
            setTimeout(function() {
                console.log("sample2-1");
                resolve("sample2-1");
            }, 16);
        });
    })
    .then(function(result) {
        console.log("result", result);
    })
    .then(function() {
        return new Promise(function(resolve, reject) {
            setTimeout(function() {
                console.log("sample2-2");
                resolve("sample2-2");
            }, 10);
        })
    })
    .then(function(result) {
        console.log("result", result);
    })
    .then(function() {
        return new Promise(function(resolve, reject) {
            setTimeout(function() {
                console.log("sample2-3");
                resolve("sample2-3");
            }, 5);
        });
    })
    .then(function(result) {
        console.log("result", result);
    });
console.log("end");

これが

// まず、Promiseを返す関数を定義
function taskA() {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            console.log("sample2-1");
            resolve("sample2-1");
        }, 16);
    })
}
function taskB() {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            console.log("sample2-2");
            resolve("sample2-2");
        }, 25);
    })
}
function taskC() {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            console.log("sample2-3");
            resolve("sample2-3");
        }, 5);
    })
}

// 逐次処理を行うやつ
async function taskSample1() {
    // 1つずつ実行
    const res1 = await taskA();
    console.log("res1:", res1);
    const res2 = await taskB();
    console.log("res2:", res2);
    const res3 = await taskC();
    console.log("res3;", res3);

    // 配列に設定して順次実行
    const taskList = [
        taskA, taskB, taskC
    ];
    for (let i=0;i<taskList.length;i++) {
        const res = await taskList[i]();
        console.log(`res${i}=`, res);
    }
}

// 実行
console.log("start");
taskSample1();
console.log("end");

こうなる
「async」を定義した関数はPromiseを返すようになるらしい、
また「await」は処理結果を返すまで待機してくれるとのこと
基本的には両方セットで使うみたい。

fetchを使う場合は

async function getRequest() {
    const response = await fetch("http://127.0.0.1:8080/sample_api1", {
        method: "POST", // *GET, POST, PUT, DELETE, etc.
        mode: "cors", // no-cors, cors, *same-origin
        cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
        credentials: "same-origin", // include, same-origin, *omit
        headers: {
            "Content-Type": "application/json; charset=utf-8"
        },
        redirect: "follow", // manual, *follow, error
        referrer: "no-referrer", // no-referrer, *client
        //body: JSON.stringify("{}"), // 本文のデータ型は "Content-Type" ヘッダーと一致する必要があります
    });

    const data = await response.json();
    console.log(data);
}

console.log("start");
for (let i=0;i<5;i++) {
    getRequest();
}
console.log("end");

うん、なんとなく同期処理っぽくかけるのが良い感じですね(^o^)
今回は記載しませんがPromise.allで複数の並列処理後の結果を取得してごにょごにょとかいうのもやってみよう

所感

結構スッキリかけるようになったようになっています。
ただ、Promiseの仕組みを十分に理解することやエラーの箇所の記載がないようにエラーに関する挙動をどうするかを今後検討していきたい。

javascriptのfetchを使ってAPIより結果を取得

概要

fetch使ってみたい

APIはgo言語で作成した適当なやつ

サーバ側
package main

import (
	"encoding/json"
	"log"
	"math/rand"
	"net/http"
	"time"
)

func main() {
	http.HandleFunc("/sample_api1", sampleAPI1)
	http.HandleFunc("/sample_api2", sampleAPI2)
	http.HandleFunc("/sample_api3", sampleAPI3)
	http.ListenAndServe("127.0.0.1:8080", nil)
}

// Response ...
type Response struct {
	Status int    `json:"status"`
	Rssult string `json:"result"`
}

func sampleAPI1(w http.ResponseWriter, r *http.Request) {

	//if r.Method == http.MethodOptions {
	//	return
	//}
	log.Println("api1", r.Method)
	rand.Seed(time.Now().UnixNano())
	time.Sleep(time.Duration(int(rand.Intn(5))) * time.Second)
	response := Response{http.StatusOK, "ok1"}
	res, _ := json.Marshal(response)

	r.Close = true
	defer r.Body.Close()
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Headers", "*")
	w.Header().Set("Accept", "application/json")
	w.Header().Set("Content-Type", "application/json")
	w.Write(res)

}
func sampleAPI2(w http.ResponseWriter, r *http.Request) {

	//if r.Method == http.MethodOptions {
	//	return
	//}
	log.Println("api2", r.Method)

	rand.Seed(time.Now().UnixNano())
	time.Sleep(time.Duration(int(rand.Intn(5))) * time.Second)
	response := Response{http.StatusOK, "ok2"}
	res, _ := json.Marshal(response)

	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Headers", "*")
	w.Header().Set("Content-Type", "application/json")
	w.Write(res)
}
func sampleAPI3(w http.ResponseWriter, r *http.Request) {

	//if r.Method == http.MethodOptions {
	//	return
	//}
	log.Println("api3", r.Method)

	rand.Seed(time.Now().UnixNano())
	time.Sleep(time.Duration(int(rand.Intn(5))) * time.Second)
	response := Response{http.StatusOK, "ok3"}
	res, _ := json.Marshal(response)

	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Headers", "*")
	w.Header().Set("Content-Type", "application/json")
	w.Write(res)
}

やって置かないとポートが違うとかなんとかでCORSエラーで弾かれる

javascript(Promise.all)
unction taskA() {
       
    return fetch("http://127.0.0.1:8080/sample_api1", {
        method: "GET", // *GET, POST, PUT, DELETE, etc.
        mode: "cors", // no-cors, cors, *same-origin
        cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
        credentials: "same-origin", // include, same-origin, *omit
        headers: {
            "Content-Type": "application/json; charset=utf-8",
        },
        redirect: "manual", // manual, *follow, error
        referrer: "no-referrer", // no-referrer, *client
        //body: JSON.stringify("{}"), // 本文のデータ型は "Content-Type" ヘッダーと一致する必要があります
    })
    .then(function(response) {
        console.log("taskA");
        return response.json();
    });
    
    
}
function taskB()  {

   return fetch("http://127.0.0.1:8080/sample_api2", {
        method: "GET", // *GET, POST, PUT, DELETE, etc.
        mode: "cors", // no-cors, cors, *same-origin
        cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
        credentials: "same-origin", // include, same-origin, *omit
        headers: {
            "Content-Type": "application/json; charset=utf-8",
        },
        redirect: "manual", // manual, *follow, error
        referrer: "no-referrer", // no-referrer, *client
        //body: JSON.stringify("{}"), // 本文のデータ型は "Content-Type" ヘッダーと一致する必要があります
    })
    .then(function(response) {
        console.log("taskB");
        return response.json();
    });

}
function taskC()  {

   return fetch("http://127.0.0.1:8080/sample_api3", {
        method: "GET", // *GET, POST, PUT, DELETE, etc.
        mode: "cors", // no-cors, cors, *same-origin
        cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
        credentials: "same-origin", // include, same-origin, *omit
        headers: {
            "Content-Type": "application/json; charset=utf-8",
        },
        redirect: "manual", // manual, *follow, error
        referrer: "no-referrer", // no-referrer, *client
        //body: JSON.stringify("{}"), // 本文のデータ型は "Content-Type" ヘッダーと一致する必要があります
    })
    .then(function(response) {
        console.log("taskC");
        return response.json();
    });

}

// 並列ですべて完了後にレスポンスを返却
console.log("start");
Promise.all([
    taskA(), taskB(), taskC()
]).then(function(data) {
    console.log("result start");
    console.log(data);
    console.log("result end");
});
console.log("end");

start
end
taskB
taskC
taskA
result start
(3) [{…}, {…}, {…}]0: {status: 200, result: "ok1"}1: {status: 200, result: "ok2"}2: {status: 200, result: "ok3"}length: 3__proto__: Array(0)
result end

※逐次処理も同じ感じで対応できそう

所感

今までajaxのcallbackでやってた部分が多いため、Promiseに対応していかないといけないが
ちょっと仕組みが難しく感じる
少しずつ確認して理解していくしかない…

javascriptのPromiseとかいうのを今更少しだけ学習する

なんか

知らんうちにfetchとか出てるんだけどPromiseとかいうやつ返すんですけど
この辺の使い方とか知らないとjqueryajaxしか使えなくなってくるのは恥ずかしい

Promise

非同期処理するやつ
Promiseで実行した結果はresolveが正常時、rejectが異常時に設定しないと取得できないらしい

サンプル

1つの処理についての非同期処理
unction sampleTask1() {
    return new Promise(function(resolve, reject) {
        setTimeout(function () {
            console.log('sample1');
            resolve("sample1");
        }, 3000);
    });
}

console.log("start");

sampleTask1()
    .then(function(result) {
        console.log("result", result);
    })
    .catch(function(error) {
        console.log("error");
    });

console.log("end");

start
end
sample1
result sample1

※単純に「new Promise」のオブジェクトより結果を判定する

複数の処理を非同期内で逐次処理で行う
console.log("start");
Promise.resolve()
    .then(function() {
        return new Promise(function(resolve, reject) {
            setTimeout(function() {
                console.log("sample2-1");
                resolve("sample2-1");
            }, 16);
        });
    })
    .then(function(result) {
        console.log("result", result);
    })
    .then(function() {
        return new Promise(function(resolve, reject) {
            setTimeout(function() {
                console.log("sample2-2");
                resolve("sample2-2");
            }, 10);
        })
    })
    .then(function(result) {
        console.log("result", result);
    })
    .then(function() {
        return new Promise(function(resolve, reject) {
            setTimeout(function() {
                console.log("sample2-3");
                resolve("sample2-3");
            }, 5);
        });
    })
    .then(function(result) {
        console.log("result", result);
    });
console.log("end");

start
end
sample2-1
result sample2-1
sample2-2
result sample2-2
sample2-3
result sample2-3

順番に処理を行うため、1つ前の実行結果を次の処理で取得するようになっていて、最後に一括で取得などを行いたい場合は少し工夫する必要がある。

複数の処理を実行し、全ての処理が完了後に結果を取得
console.log("start");
Promise.all([
    
     new Promise(function(resolve, reject) {
            setTimeout(function() {
                console.log("sample2-1");
                resolve("sample2-1");
            }, 16);
        })
    , new Promise(function(resolve, reject) {
            setTimeout(function() {
                console.log("sample2-2");
                resolve("sample2-2");
            }, 10);
        })
    ,  new Promise(function(resolve, reject) {
            setTimeout(function() {
                console.log("sample2-3");
                resolve("sample2-3");
            }, 25);
        })
    
]).then(function(data) {
    console.log("result start");
    console.log(data);
    console.log("result end");
});
console.log("end");
|<
↓
>||
start
end
sample2-2
sample2-1
sample2-3
result start
 (3) ["sample2-1", "sample2-2", "sample2-3"]0: "sample2-1"1: "sample2-2"2: "sample2-3"length: 3__proto__: Array(0)
result end

すべての処理が並列で動作し、最後に処理を実行するため、最後に取得するまでは値を取得できない
まあ、なんか方法はあるとは思うが…

所感

allによる同時並列と逐次処理で次の処理へ流せるのは少しだけ理解した
次はfetchを利用した手法で見てみる

golangのpanic発生しても処理を続行したい

golangでのエラーとかって

基本的にはエラーオブジェクトのチェックしかしていない

panic発生したら

落ちます

package main

import (
    "log"
)

func main() {
    log.Println("start")


    // 意図的にpanicを起こす
    panic("aaaa")
    //var a *interface{}
    //*a = 0
    //x := 10
    //y := 0
    //b := x / y
    //log.Println(b)

    log.Println("end")
}

2019/08/14 10:04:05 start
panic: aaaa

goroutine 1 [running]:
main.main()
	/sample2-b.go:12 +0x79
exit status 2

そうならないようにerrオブジェクトや変数のチェックで抑制していますが
まれになんらかの理由でオブジェクトにnullが挿入される自体が発生してpanicがおきたらマズい

javaのtry-catchとかあればよいがそういうのはないため、
deferとrecoverを併用することで対応できるとのこと

ドキュメントより以下、引用(http://golang.jp/effective_go#recover

panicが呼び出されたとき(これには、配列のインデックスが範囲外であるときや、型アサーションに失敗したような暗黙的なものも含む)は、すぐさま、カレントの関数を停止し、ゴルーチンのスタックの巻き戻しを開始します。その途中、遅延指定されている関数をすべて実行します。この巻き戻しがゴルーチンのスタックの先頭にたどり着くと、プログラムは終了します。ただし、組み込み関数recoverを使うことで、ゴルーチンの制御を取り戻し、通常の実行を再開させることが可能です。

書き直し

package main

import (
	"log"
	"fmt"
	"runtime"
)

func main() {
	log.Println("start")

	// 今回は即時関数にしているがerrorの戻り値を取得できるならなんでもよい
	err := func() (errRes error) {
		// panic発生時に補足するやつ
		defer func() {
			if err := recover(); err != nil {
				// エラー情報を戻り値のerrResへ設定
				errRes = fmt.Errorf("error: %s", err)

				// stack trace
				for i:=0;;i++ {
					_, file, line, ok := runtime.Caller(i)
					if ok == false {
						break
					}
					log.Printf("depth: %d, line: %4d, file:%v\n", i, line, file)
				}
			}
		}()

		// 意図的にpanicを起こす
		//panic("aaaa")
		//var a *interface{}
		//*a = 0
		x := 10
		y := 0
		b := x / y
		log.Println(b)

		// ここまできたら正常
		return nil
	}()

	// errorチェック
	if err != nil {
		log.Println(err)
	}

	log.Println("end")
}

2019/08/14 10:13:38 start
2019/08/14 10:13:38 depth: 0, line:   22, file: /work/golang/sample2.go
2019/08/14 10:13:38 depth: 1, line:  522, file:/usr/local/Cellar/go/1.12.7/libexec/src/runtime/panic.go
2019/08/14 10:13:38 depth: 2, line:   61, file:/usr/local/Cellar/go/1.12.7/libexec/src/runtime/panic.go
2019/08/14 10:13:38 depth: 3, line:   37, file:/work/golang/sample2.go
2019/08/14 10:13:38 depth: 4, line:   42, file:/work/golang/sample2.go
2019/08/14 10:13:38 depth: 5, line:  200, file:/usr/local/Cellar/go/1.12.7/libexec/src/runtime/proc.go
2019/08/14 10:13:38 depth: 6, line: 1337, file:/usr/local/Cellar/go/1.12.7/libexec/src/runtime/asm_amd64.s
2019/08/14 10:13:38 error: runtime error: integer divide by zero
2019/08/14 10:13:38 end

Webフレームワークとかは

API配下のpanicは拾ってくれるが、内部でgoroutineなどを任意で定義した場合にpanicを起こすと
Webフレームワークのアプリ自体が停止する可能性がある・・・

所感

なんかスマートじゃない感じ…
現状、これしか見つからないからこの方法で対応を試みます。

golangでUUIDの生成をライブラリでお試し

仕事でコード書くより

設計の仕事ばっかり、スケジュール管理とかめんどくさいので
他の人やってくんないかな…

UUIDって?

UUID(Universally Unique Identifier)とは、ソフトウェア上でオブジェクトを一意に識別するための識別子である。

*1

ざっくりいうとユニークIDみたいやつ
基本的にはsha1とかmd5とか乱数で生成していたけど
そういったものにフォーマットがついた感じ

例:3cc807ab-8e31-3071-aee4-f8f03781cb91

バージョン

現在1から5までの方法がある

確認用ライブラリ

https://github.com/google/uuid
今度改めて自身でアルゴリズムは検討するが今回はちょっとお試しでやってみる

ソース

package main

import (
    "github.com/google/uuid"
    "fmt"
)

func main() {
    fmt.Println("version1 NewUUID --")
    for i:=0;i<10;i++ {
        uuidObj, _ := uuid.NewUUID()
        fmt.Println("  ", uuidObj.String())
    }

    fmt.Println("version2 NewDCESecurity --")
    for i:=0;i<10;i++ {
        uuidObj, _ := uuid.NewUUID()
        domain := uuidObj.Domain()
        id := uuidObj.ID()

        uuidObj2, _ := uuid.NewDCESecurity(domain, id)
        fmt.Println("  ", uuidObj2.String())
    }

    fmt.Println("version3 NewMD5 --")
    for i:=0;i<10;i++ {
        uuidObj, _ := uuid.NewUUID()
        data := []byte("wnw8olzvmjp0x6j7ur8vafs4jltjabi0")
        uuidObj2 := uuid.NewMD5(uuidObj, data)
        fmt.Println("  ", uuidObj2.String())
    }

    fmt.Println("version5 NewSHA1 --")
    for i:=0;i<10;i++ {
        uuidObj, _ := uuid.NewUUID()
        data := []byte("wnw8olzvmjp0x6j7ur8vafs4jltjabi0")
        uuidObj2 := uuid.NewSHA1(uuidObj, data)
        fmt.Println("  ", uuidObj2.String())
    }

    fmt.Println("version4 NewRandom --")
    for i:=0;i<10;i++ {
        uuidObj, _ := uuid.NewRandom()
        fmt.Println("  ", uuidObj.String())
    }

}

結果

mshige1979MBA:golang matsumotoshigeharu$ go run sample1.go
version1 NewUUID --
   ef45b54c-9f70-11e9-a730-6476baad914e
   ef45c294-9f70-11e9-a730-6476baad914e
   ef45c2b2-9f70-11e9-a730-6476baad914e
   ef45c2c6-9f70-11e9-a730-6476baad914e
   ef45c2e4-9f70-11e9-a730-6476baad914e
   ef45c2f8-9f70-11e9-a730-6476baad914e
   ef45c316-9f70-11e9-a730-6476baad914e
   ef45c334-9f70-11e9-a730-6476baad914e
   ef45c352-9f70-11e9-a730-6476baad914e
   ef45c366-9f70-11e9-a730-6476baad914e
version2 NewDCESecurity --
   ef45c38e-9f70-21e9-a730-6476baad914e
   ef45c3ac-9f70-21e9-a730-6476baad914e
   ef45c3ca-9f70-21e9-a731-6476baad914e
   ef45c3e8-9f70-21e9-a732-6476baad914e
   ef45c410-9f70-21e9-a732-6476baad914e
   ef45c442-9f70-21e9-a732-6476baad914e
   ef45c46a-9f70-21e9-a733-6476baad914e
   ef45c49c-9f70-21e9-a733-6476baad914e
   ef45c4c4-9f70-21e9-a734-6476baad914e
   ef45c4ec-9f70-21e9-a735-6476baad914e
version3 NewMD5 --
   3cc807ab-8e31-3071-aee4-f8f03781cb91
   7e7e001e-6957-38d5-b035-41926dd035dd
   91d52425-9470-3e2b-8e5f-649b7b4ec795
   157ffb9e-d6b2-3b99-9fca-1d347f60b3e3
   33b0480d-6d5f-358a-a37a-893e5850fa62
   4b41d96b-dd72-3314-9cc2-1ab241eacb30
   9337ce23-6909-3137-98d2-a9372bf57692
   1e15f3d0-a040-3eca-a8bc-c677bc8bc619
   b90f3b5d-059c-3c0e-b3d8-85c577763bf6
   f741b68d-a9d2-3396-b499-745920a718ff
version5 NewSHA1 --
   13f575fa-02d7-5c38-8e66-48524dd233a4
   a56079b2-5373-5656-911a-483e3a92f19c
   18c2d54b-1a94-5928-8a4a-2f3dd5fc3e57
   8ac4f8a2-89b8-5ea3-81eb-d1654deaab51
   bb6bff8b-615f-5791-a9fb-e3543fd9d02e
   8209f28f-ccc9-5a90-beaf-d7e8e9927183
   387ab566-8b80-5c6c-a156-8e49a5c9c3fe
   75a4de2d-8049-5bb1-80c9-7250959af3d2
   5991cc2e-2bac-5f83-9ae0-b4a45882a11a
   b8e33f96-449d-5972-8c9c-98b0487549dd
version4 NewRandom --
   01a2c8b4-e3ec-4df5-a027-b7ffe5c6ed5d
   eb2aa249-3614-4833-b979-99c87c4189a8
   4c8bda02-4b27-460a-b46f-d65b4e4f5e48
   23df6b4c-e10f-4bcd-b935-0224f3216680
   2ab1a839-08b2-4069-9bd7-a772c5934e66
   dab1ade8-a446-4609-844b-257a7ab1ba0b
   eb770f37-a59a-4888-9789-d585f514ae93
   b9999fdb-cd20-4bdb-b671-6228667a6746
   8160d492-1ead-4d33-b4e8-d242cf2df332
   63b96ec6-e9d7-4fa4-abb7-31b9e12fca0d

*1:出典: フリー百科事典『ウィキペディアWikipedia)』

PlantUMLをVisualStudioCodeで書く

PlantUMLって

なんかUMLをテキストで書いて絵にするツールらしい

環境

今回はMacでやります

インストール

graphvizをインストール
brew install graphviz

デモ

画面

f:id:m_shige1979:20181103220003p:plain

動画


plantuml

所感

Excelファイルによるドキュメント資料からの脱却を目指したい
まあ、まだまだ無理でしょうけど少しづつやればなんとか…