typeof Diary

VimとかJSとか。やったことのメモ。自分のため。

今更WebComponentsの触り

わりとガンガンjQueryな、とくにUIライブラリも使っていない。(jQueryUIはあるけど)
いろいろと辛い状況なやつ。

画面追加がある度に、ほぼその画面に合わせてCSSも書きつつ。
レイアウト指示はそこそこ細かく、px単位でたまに指摘される。

そんなのが続くと画面追加があるたびに、HTML、CSS書くのめんどくさい!!!という感情が湧いてくるわけです。
WebComponentsって楽できないのかな・・・がはじまり。

書き方基礎

<hello-world/>
class HelloWorld extends HTMLElement {
  constructor() {
    super()
    const shadowRoot = this.attachShadow({ mode: 'open" })
    shadowRoot.innerHTML = `<h1>Hello World</h1>`
  }
}

customElements.define('hello-world', HelloWorld)

書き方は意外と簡単ですね。

プロパティ与えたい

React, Vue, Angularなんかを書いていると、コンポーネントにpropsを渡して描画することが多々あります。
似たようなことできないの?って思ったんですが、厳しそうです。

<hello-world data-name="Bob"/>
const HelloWorld extends HTMLElement {
  constructor() {
    super()
    
    this.myName = this.getAttribute('data-name')
      ? this.getAttribute('data-name')
      : ''

    const shadowRoot = this.attachElement({ mode: 'open' })
    shadowRoot.innerHTML = this.template()
  }

  template() {
    return `<h1>Hello ${this.myName}`
  }
}

customElements.define('hello-world', HelloWorld)

Attributeでプロパティは渡せるけど、取り出したらこれ文字列ですよね。
無理矢理JSONなんか渡したらいけるのかもしれないけど、そこまでするか・・・?

ちょっとしたステータスで色変えたいよ。とか、そんなレベルで使うのが良いのかなと思いました。

いわゆるJS FW系で扱ってるようなコンポーネントとは似て非なるもの。って感じでしょうか。

まだ詳しくは調べてないけど、間違ってたらすいません。

A Tour of Goを完走した

1周目はよくわからなかったけど、よく読んで2周目やってみたら意外と解けました。

ということで、一通りやってみたコードのまとめ。
もっとスマートにできたりすると思う。

Loops and Functions

関数とループを使った簡単な練習として、平方根の計算を実装してみましょう: 数値 x が与えられたときに z² が最も x に近い数値 z を求めたいと思います。

func Sqrt(x float64) float64 {
    z := 1.0
    for i := 0; i < 10; i++ {
        z -= (z*z - z) / (2 * z)
    }
    return z
}

次に値が変化しなくなった (もしくはごくわずかな変化しかしなくなった) 場合にループを停止させます。 それが 10 回よりも多いか少ないかを確認してください。

この文章が本当に理解できず、悩みました。
「ごくわずかな変化ってなんやねん」って感じで・・・。

下の方にニュートン法のことが触れられていて、そっちを読むとなんとなく理解し始めました。

func Sqrt(x float64) float64 {
    z := 1.0
    var prev float64
    for i := 0; i < 10; i++ {
        z -= (z*z - z) / (2 * z)

        if math.Abs(prev-z) < 1e-10 {
            fmt.Printf("%d回目\n" , i+1)
            break
        }

        prev = z
    }
    return z
}

どんなもんなのかを課題解いたよ!って記事のコードいくつか読んでみて噛み砕いてからやりました。
ただ、1e-10のところが実装者によって様々で、1e-101e-60.0001とかいろいろあって、理解していないときは「なんで?」ってなりました。
ここが誤差の許容範囲みたいな感じで理解してます。

Slices

Pic 関数を実装してみましょう。 このプログラムを実行すると、生成した画像が下に表示されるはずです。

ここは問題文通り、+ヒント参考にしながらやればなんとかなりました。

func Pic(dx, dy, int) [][]uint8 {
    pic := make([][]uint8, dy)

    for y, _ := range pic {
        pic[y] = make([]uint8, dx)

        for x, _ := range pic[y] {
            pic[x][y] = uint8(x*y)
        }
    }

    return pic
}

uint8(xxx)のところは、

生成する画像は、好きに選んでください。例えば、面白い関数に、 (x+y)/2 、 x*y 、 xy などがあります。

の部分なので、好きな計算式入れてあげると良いです。
画像変わって面白いですよ。なんならここに示されている計算式以外でも変な画像できます。

Maps

WordCount 関数を実装してみましょう。string s で渡される文章の、各単語の出現回数のmapを返す必要があります。 wc.Test 関数は、引数に渡した関数に対しテストスイートを実行し、成功か失敗かを結果に表示します。

一番分かりやすかった気がするのは、普段JSで大体なんでもオブジェクトでKey:Valueにしてなんかしちゃうのが原因?

func WordCount(s string) map[string]int {
    wordList := strings.Fields(s)
 
    m := make(map[string]int)
    for _, word := range wordList {
        if _, exist := m[word]; exist {
            m[word]++
        } else {
            m[word] = 1
        }
    }
 
    return m
}

Fibonacci closure

fibonacci (フィボナッチ)関数を実装しましょう。この関数は、連続するフィボナッチ数(0, 1, 1, 2, 3, 5, ...)を返す関数(クロージャ)を返します。

クロージャの問題。
フィボナッチ数列自体は分かってたのですが、最初の0,1は固定なんですね・・・。

func fibonacci() func() int {
    fib := 0
    result := [2]int{0,0}

    return func() int {
        if fib == 1 {
            result[1] = 1
        } else {
            w := result[1]
            result[1] = result[0] + result[1]
            result[0] = w
        }
        fib++
        return result[1]
    }
}

さすがにもっとスマートに書けるんじゃないかなこれ。

Stringers

IPAddr 型を実装してみましょう IPアドレスをドットで4つに区切った( dotted quad )表現で出力するため、 fmt.Stringer インタフェースを実装してください。 例えば、 IPAddr{1, 2, 3, 4} は、 "1.2.3.4" として出力するようにします。

func (ip IPAddr) String() string {
    return fmt.Sprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3])
}

Errors

Sqrt 関数を 以前の演習 からコピーし、 error の値を返すように修正してみてください。 Sqrt は、複素数をサポートしていないので、負の値が与えられたとき、nil以外のエラー値を返す必要があります。

type ErrNegativeSqrt float64

func (x ErrNegativeSqrt) Error() string {
    return fmt.Sprintf("cannot Sqrt negative number %f", float64(x))
}

func Sqrt(x float64) (float64, error) {
    if x < 0 {
        return 0, ErrNegativeSqrt(x)
    }

    z := 1.0
    var prev float64
    for i := 0; i < 10; i++ {
        z -= (z*z - z) / (2 * z)

        if math.Abs(prev-z) < 1e-10 {
            fmt.Printf("%d回目\n" , i+1)
            break
        }

        prev = z
    }
    return z, nil
}

Readers

ASCII文字 'A' の無限ストリームを出力する Reader 型を実装してください。

無限ストリームがイマイチピンとこなくて調べました。 ほぼそのままの意味でした()

b[i] = "A"としていてtype errorになって、ここではじめて'A'であることに気付いた。
学び。

otiai10.hatenablog.com

func (r MyReader) Read(b []byte) (int, error) {
    for i := range b {
        b[i] = 'A'
    }
    return len(b), nil
}

rot13Reader

io.Reader を実装し、 io.Reader でROT13 換字式暗号( substitution cipher )をすべてのアルファベットの文字に適用して読み出すように rot13Reader を実装してみてください。

type rot13Reader struct {
    r io.Reader
}

func (r rot13Reader) Read(b []byte) (n int, err error) {
    n, err = r.r.Read(b)
    if err != nil {
        return
    }

    for i, c := range b[:n] {
        if 'A' <= c && c <= 'Z' {
            b[i] = (c-'A'+13)%26 + 'A'
        } else if 'a' <= c && c <= 'z' {
            b[i] = (c-'a'+13)%26 + 'a'
        }
    }
    return
}

問題文中にあるgzip.NewReaderへのリンクがあったので、コード読んでると、r.r.Readのヒントが得られました。
読んだら書けました。

Image

前に解いた、画像ジェネレーターを覚えていますか? 今回は、データのスライスの代わりに image.Image インタフェースの実装を返すようにしてみましょう。 自分の Image 型を定義し、 インタフェースを満たすのに必要なメソッド を実装し、 pic.ShowImage を呼び出してみてください。

ドキュメント読んだらそれっぽくできました。
とりあえず、w, hだけ持たせて、呼び出しで大きさ決めれるようにはしておきました。

import (
    "golang.org/x/tour/pic"
    "image"
    "image/color"
)

type Image struct {
    w int
    h int
}

func (i Image) ColorModel() color.Model {
    return color.RGBAModel
}
func (i Image) Bounds() image.Rectangle {
    return image.Rect(0, 0, i.w, i.h)
}
func (i Image) At(x int, y int) color.Color {
    return color.RGBA{0, 0, uint8(x ^ y), uint8(x ^ y)}
}

func main() {
    m := Image{180, 180}
    pic.ShowImage(m)
}

Exercise: Equivalent Binary Trees

https://go-tour-jp.appspot.com/concurrency/7
問題文長いので↑で確認してください。。。

Tree.Left, Tree.Rightが*Treeであることに気付けたら、あとは早かったです。

package main

import (
    "fmt"
    "golang.org/x/tour/tree"
)

// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
    recursiveWalk(t, ch)
    close(ch)
}

func recursiveWalk(t *tree.Tree, ch chan int) {
    if t.Left != nil {
        recursiveWalk(t.Left, ch)
    }
    ch <- t.Value
    if t.Right != nil {
        recursiveWalk(t.Right, ch)
    }
}

// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
    ch1 := make(chan int)
    ch2 := make(chan int)

    go Walk(t1, ch1)
    go Walk(t2, ch2)

    for {
        c1, ok1 := <-ch1
        c2, ok2 := <-ch2
        switch {
        case !ok1, !ok2:
            return ok1 == ok2
        case c1 != c2:
            return false
        }
    }
}

func main() {
    ch := make(chan int)
    go Walk(tree.New(1), ch)
    for c := range ch {
        fmt.Println(c)
    }

    fmt.Println(Same(tree.New(1), tree.New(1)))
    fmt.Println(Same(tree.New(1), tree.New(2)))
}

Exercise: Web Crawler

package main

import (
    "fmt"
    "sync"
    "time"
)

type Fetcher interface {
    // Fetch returns the body of URL and
    // a slice of URLs found on that page.
    Fetch(url string) (body string, urls []string, err error)
}

// Crawl uses fetcher to recursively crawl
// pages starting with url, to a maximum of depth.
func Crawl(url string, depth int, fetcher Fetcher) {
    cacheUrl := make(map[string]int)
    var mux sync.Mutex

    var crawl func(string, int)
    crawl = func(url string, depth int) {
        if depth <= 0 {
            return
        }

        if _, ok := cacheUrl[url]; ok {
            return
        }

        mux.Lock()
        cacheUrl[url]++
        mux.Unlock()
     
        body, urls, err := fetcher.Fetch(url)
        if err != nil {
            fmt.Println(err)
            return
        }

        fmt.Printf("found: %s %q\n", url, body)

        for _, u := range urls {
            go crawl(u, depth-1)
        }

    }

    go crawl(url, depth)
    time.Sleep(time.Second)
    fmt.Println(cacheUrl)
    return
}

func main() {
    Crawl("https://golang.org/", 4, fetcher)
}

// fakeFetcher is Fetcher that returns canned results.
type fakeFetcher map[string]*fakeResult

type fakeResult struct {
    body string
    urls []string
}

func (f fakeFetcher) Fetch(url string) (string, []string, error) {
    if res, ok := f[url]; ok {
        return res.body, res.urls, nil
    }
    return "", nil, fmt.Errorf("not found: %s", url)
}

// fetcher is a populated fakeFetcher.
var fetcher = fakeFetcher{
    "https://golang.org/": &fakeResult{
        "The Go Programming Language",
        []string{
            "https://golang.org/pkg/",
            "https://golang.org/cmd/",
        },
    },
    "https://golang.org/pkg/": &fakeResult{
        "Packages",
        []string{
            "https://golang.org/",
            "https://golang.org/cmd/",
            "https://golang.org/pkg/fmt/",
            "https://golang.org/pkg/os/",
        },
    },
    "https://golang.org/pkg/fmt/": &fakeResult{
        "Package fmt",
        []string{
            "https://golang.org/",
            "https://golang.org/pkg/",
        },
    },
    "https://golang.org/pkg/os/": &fakeResult{
        "Package os",
        []string{
            "https://golang.org/",
            "https://golang.org/pkg/",
        },
    },
}

合ってるかわからん!
それっぽいはず・・・。

一通り終えて

コードこれで本当に合っているのかはわからないけど、1回目に書いたものということで残しておきます。

これで、みんなのGo言語を読み進めるスタート地点に立てた気がします。。。   本にもあったけど、また慣れてからやれば、もっと違う感じになると思うので、それはまた追々。

とりあえず、終わったよ報告でした。

GoでString to Intしたい

夏季課題として与えられたちょっとしたプログラミングテスト。
で慣れ親しんだJSではなく、わざとGoで挑戦。
せっかく始めたし、知識つけるために。

そんな中、StringをIntにしないといけない場面に出くわして調べた。 (Tour of Goしかやってないぐらいの知識なので)

parseInt的なことやるときはstrconv.Atoi(string)でできることが分かった。
部分的にはこんな場面。

package main

import (
    "fmt"
    "strings"
    "strconv"
)

func main() {
    const S = "20 50 33 50 60"

    numberList := strings.Fields(S)

    sum := 0
    for _, number := range numberList {
        i, _ := strconv.Atoi(number)
        sum += i
    }

    fmt.Println(sum)
}

parseInt的なことやるときはstrconv.Atoi(string)

覚えました。

別言語で当たり前にやってることだけど、こうやってやり方覚えていくのは楽しい。

Goはじめた

先日、「みんなのGo言語」を購入。

このお盆休みの9連休でやってやろうと思ってやり始めてます。
進めていくと、まずは「A Tour of Go」をやろうとのことなので、ちょっとずつ進めていきました。

一通り最後まで進めたはいいものの、まだまだ理解は追いついていません。
まだ慣れていないからっていうのもあるし、書いているうちに慣れるでしょう・・・。

それはそうと、Tour of GoのExercise難しくないですか?
僕のレベルが低いだけ?

解けたの2問しかない。

最初のforのやつと、mapのやつ。
forのやつも差がうんぬんの意味がわからなくてできてないし、
できそうだったフィボナッチもできなかった。

問題読んでも何をしたらいいのかサッパリで、自分のレベルの低さに嫌気がさしました。

こういった問題が解けないんだなと、改めて苦手を意識。
trackとかの問題も解くのが苦手で、同じ感じですね。
AtCoderなんかも同じ感じ。

これも数こなして慣れるしかないんでしょうか。

まぁ、さすがに克服したいので、少しずつやっていきたいと思います。

Tour of GoのExercise、自力で解きたいなぁ・・・。

VuexのcreateNamespacedHelpers、同名どうするよ

昨日書いた「VuexのcreateNamespacedHelpersでdispatchの記述を短くしたい」なんですが。
一つ考慮が漏れてました。

namespaceがあることで同じ名前のアクション名でも問題なかったのが、あれをやると死にますね。
(よくよく考えたら当たり前)

例えば、それぞれのモジュールでステートを初期化するアクションがあるとすると・・・

// foo/types.js
export const namespace = 'foo'
export const RESET = 'RESET'

// hoge/types.js
export const namespace = 'hoge'
export const RESET = 'RESET' 
import * as fooTypes from '@/store/modules/Foo/types'
import * as hogeTypes from '@/store/modules/Hoge/types'
import { createNamespacedHelpers } from 'vuex'

const { mapActions: mapActionsOfFoo } = createNamespacedHelpers(fooTypes.namespace)
const { mapActions: mapActionsOfHoge } = createNamespacedHelpers(hogeTypes.namespace)

// ...
methods: {
  ...mapActionsOfFoo([fooTypes.RESET]),
  ...mapActionsOfHoge([hogeTypes.RESET])
}

この場合、同じRESETマッピングされてしまうので、結果的にはHoge側がマッピングされてしまいます。

防ぐには、

  • FOO_RESETとかHOGE_RESETとか分けた名前にする(namespaceの意味とは)
  • mapActions({ FOO_RESET: fooTypes.RESET })みたいにマップするときに名前を変える

かなと思いますが、namespaceで得たものを自ら捨てている感じがして、なんとも言えない感じに。

記述量は減らせますが、一長一短ですね。

うーん・・・。

VuexのcreateNamespacedHelpersでdispatchの記述を短くしたい

初めてVuexを触ったとき、とくにnamespaceも使わずやってました。

ちなみにmapActionsは使わず、this.$store.dispatchでしたい派。
this.$store.dispatchの方がdispatchしてるわー!今dispatchしてるわー感があるので好き。
というのは嘘で、コード見たときに、「アクション叩いてる」っていう部分が、ぱっと見分かりやすかったってのがあります。

問題

namespaced: trueにしてみると、namespace + actionNameと書く必要がでてきます。

methods: {
  handleClickBefore(e) {
    this.$store.dispatch('actionName', payload)
  },

  handleClickAfter(e) {
    this.$store.dispatch('namespace/actionName', payload)
  }
}

こう見てみると、「そんな嫌か?」ってレベルに見えるんです。

typesを分ける

実際開発しだすと、直接文字列で指定することは少なくて、types.jsみたいなのをつくって、中にconstでミューテーションとかアクション名を書いていきます。

export const namespace = 'File/'

export const SET_FILE_LIST = 'SET_FILE_LIST'
export const FETCH_FILE_LIST = ' FETCH_FILE_LIST'

こうすると、dispatchの部分は

import * as fileTypes from '@/store/modules/File/types'
// ...
methods: {
  handleClick(e) {
    this.$dispatch(fileTypes.namespace + fileTypes.FETCH_FILE_LIST)
  }
}

このレベルだとまだマシですが、中にはPREFIXがついて長くなるアクション名がでてきます。

this.$dispatch(fooTypes.namespace + fooTypes.PREFIX_PREFIX_ACTION_NAME_FOR_XXX)

ここまでなると、さすがにdispatchが良いとは言い辛い状況になってきました。

解決

createNamespacedHelpersというのがVuexに用意されていることを知りました。
Vuex/modules

import { createNamespacedHelpers } from 'vuex'
import * as fileTypes from '@/store/modules/file/types'

const { mapActions: mapActionsOfFile } = createNamespacedHelpers(fileTypes.namspace)

//...
methods: {
  ...mapActionsOfFile([fileTypes.FETCH_FILE_LIST]),

  handleClick(e) {
    this[fileTypes.FETCH_FILE_LIST]()
  }
}

結局mapActionsに屈したわけですが、思っていたほど見辛いこともなく、楽に書けるので良いかなといった具合です。
(Vuex噛んでいるところはthis[types.XXXX]ってなるので、他とか区別できているので)

その他も

mapStatemapGetteresmapState(namespace, [xxxx])としていたのも同じく解決です。
また、複数のモジュールを使うときも明確になりますね。

import * as fileTypes from '@/store/modules/File/types'
import * as userTypes from '@/store/modules/User/types'

const { mapState: mapStateOfFile, mapGetters: mapGettersOfFile } = createNamespacedHelpers(fileTypes.namesace)
const { mapState: mapStateOfUser, mapGetters: mapGettersOfUser } = createNamespacedHelpers(userTypes.namesace)

//...
computed: {
  ...mapStateOfFile(['fileList']),
  ...mapStateOfUser(['userList']),
  ...mapGettersOfFile(['imageList', 'pdfList'])
}

みたいな具合で。
一つのモジュールしか使わないなら、import * as types from '@/store/modules/xxxx'でいいんですけどね。

参考記事

vscodevimでやってる設定

VSCode使い始めて1年ほど。
結局Vimから乗り換えたというか、両方使ってる感じではあります。

というのも、このissueにあるように、行数が多いとかなりパフォーマンスが落ちてしまって、まともにコード書けなくなるんですよね・・・。
VSCodeVIM is unusable (incredibly slow) on larger files, especially in INSERT MODE #2216

そんな中でこれだけは設定してる!というのピックアップしておきます。

設定

自分はVimでLeaderをスペースに設定しているので、それを踏襲。
<Leader> hで文頭、<Leader> lで文末をよく使ってます。
最低限、これを入れるだけでかなり使い勝手がよくなりました。
むしろ、手が勝手にこれを打つのでないと厳しい...。

そこの設定はこんな感じ。

{
  "vim.leader": "<space>",
  "vim.useSystemClipboard": true,
  "vim.normalModeKeyBindingNonRecursive": [
    {
      "before": [
        "leader",
        "h"
      ],
      "after": [],
      "commands": [
        {
          "command": "cursorHome",
          "args": []
        }
      ]
    },
    {
      "before": [
        "leader",
        "l"
      ],
      "after": [],
      "commands": [
        {
          "command": "cursorEnd",
          "args": []
        }
      ]
    }
  ]
}

キーボードショートカット

もうひとつ、Uniteで,fとかでファイラ開いてたのも似たような感じにしたくて、Shift + fでクイックオープン開くようにしました。

Shift + fはいろいろ問題あったのでやめました。。。
まずエクスプローラーでShilf + fすると、普通にFが入力されてしまうし、そもそもShift + f潰すとFが入力できない()

Ctrl + , fに変えました。ちょっと面倒かな。。。

こっちは基本設定→キーボードショートカットから、workbench.action.quickOpenの設定を変えてください。

MacのデフォがCommand + pなんですけど、片手で打ちやすいようにした感じです。
Ctrl + fが良いんですけど、Ctrl + fVimのスクロールとバッティングするので避けました・・・。

あとは

fコマンドを使うとき、自分がいかにclever-f.vimに依存してるかが分かりました。
自然とf連打してしまう・・・。VSCodeでも似たようなことしたいなーなんかちょいちょい思ってます。