Perl日記

日々の知ったことのメモなどです。Perlは最近やってないです。

Rust で HashSet の要素や HashMap のキーに使う型は Eq と Hash トレイトを実装している必要がある

HashSet in std::collections - Rust
HashMap in std::collections - Rust



自前の構造体を HashSet の要素にしたり、HashMap のキーに使用するとコンパイルエラーになる。

use std::collections::HashSet;
fn main() {
    {
        struct MyFoo {
            x: i32,
        }
        let mut hs: HashSet<MyFoo> = HashSet::new();
        hs.insert(MyFoo { x: 123 });
        hs.insert(MyFoo { x: 234 });
        for e in hs.iter() {
            println!("{}", e.x);
        }
    }
}
error[E0599]: the method `insert` exists for struct `HashSet<MyFoo>`, but its trait 
bounds were not satisfied
 --> examples\hm_error.rs:8:12
  |
4 |         struct MyFoo {
  |         ------------
  |         |
  |         doesn't satisfy `MyFoo: Eq`
  |         doesn't satisfy `MyFoo: Hash`
...
8 |         hs.insert(MyFoo { x: 123 });
  |            ^^^^^^ method cannot be called on `HashSet<MyFoo>` due to unsatisfied trait bounds
  |
  = note: the following trait bounds were not satisfied:
          `MyFoo: Eq`
          `MyFoo: Hash`
help: consider annotating `MyFoo` with `#[derive(Eq, Hash)]`
  |
4 |         #[derive(Eq, Hash)]
  |

error[E0599]: the method `insert` exists for struct `HashSet<MyFoo>`, but its trait 
bounds were not satisfied
 --> examples\hm_error.rs:9:12
  |
4 |         struct MyFoo {
  |         ------------
  |         |
  |         doesn't satisfy `MyFoo: Eq`
  |         doesn't satisfy `MyFoo: Hash`
...
9 |         hs.insert(MyFoo { x: 234 });
  |            ^^^^^^ method cannot be called on `HashSet<MyFoo>` due to unsatisfied trait bounds
  |
  = note: the following trait bounds were not satisfied:
          `MyFoo: Eq`
          `MyFoo: Hash`
help: consider annotating `MyFoo` with `#[derive(Eq, Hash)]`
  |
4 |         #[derive(Eq, Hash)]
  |

For more information about this error, try `rustc --explain E0599`.

derive で Hash と Eq をつければ良いようだ。しかしその2つだとインスタンス同士の比較ができなくて、PartialEq もつけるといいよ!、とメッセージが出るので、そのようにするとうまくいった。

        #[derive(Hash, Eq, PartialEq)]
        struct MyFoo {
            x: i32,
        }

同様に、HashMap のキーのときも同じ対応でいけた。

        #[derive(Hash, Eq, PartialEq)]
        struct MyFoo {
            x: i32,
        }
        let mut hm: HashMap<MyFoo, &str> = HashMap::new();
        hm.insert(MyFoo { x: 123 }, "123");
        hm.insert(MyFoo { x: 234 }, "234");
        for (k, v) in hm.iter() {
            println!("{}, {}", k.x, v);
        }

WebAssembly と Rust について社内で LT した

内容をメモ

  • WebAssembly とは
    • WebAssembly とは
      • ネイティブに近いパフォーマンスで動く
      • コンパイルして作るバイナリ
    • 第 4 のブラウザ用言語
      • W3C 勧告として公開
    • 対応ブラウザ
      • 最近のブラウザはすべて対応している(IE もいなくなったので本当にすべて)
    • 作成言語
      • 実際に使っているひとに聞いたアンケート結果では Rust が 1 位とのこと
    • 事例
    • WASI (WebAssembly System Interface)
      • ランタイムの三国時代 wasmer, wasmtime, wasmedge
      • コンテナのようなポータブル性
    • メリット
    • デメリット
      • なんでもかんでも改善できるわけではない
      • ブラウザによって JS よりも早くなったり遅くなったりするらしい
  • Rust とは
    • Rust とは
      • 6 年連続、最も愛された(=仕事で使いたい)言語 1 位
    • 所感
      • とにかく難しく感じる
  • WebAssembly + Rust

Rust と WebAssembly で ボタンを getElementById したり click 属性をつけたりするサンプルメモ

Rust の WebAssembly で、ボタンを押すと、div#msgdiv にテキストを入れて、window.alert() を実行するサンプルメモ。

trunk を使用している。

index.html
<!DOCTYPE html>
<html>

<head></head>

<body>
  <div id="msgdiv"></div>
  <input type="button" value="botan" id="foobtn">
</body>

</html>
Cargo.toml
[package]
name = "click-test"
version = "0.1.0"
edition = "2021"

# [lib]
# crate-type = ["cdylib", "rlib"]

[dependencies]
# log = "0.4.17"
# wasm-logger = "0.2.0"
# web-sys = "0.3.57"
wasm-bindgen = "0.2.80"

[dependencies.web-sys]
version = "0.3.57"
features = [
  'Window',
  'Document',
  'Element',
  'HtmlElement'
]
src/main.rs
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use web_sys::{Document, HtmlElement, Window};

#[wasm_bindgen]
extern "C" {
    fn alert(s: &str);
}

fn window() -> Window {
    web_sys::window().unwrap()
}

fn document() -> Document {
    window().document().unwrap()
}

fn body() -> HtmlElement {
    document().body().unwrap()
}

pub fn main() {
    let cb = Closure::wrap(Box::new(move || {
        let el = document().get_element_by_id("msgdiv").unwrap();
        // テキストを入れる
        el.set_text_content(Some("Hello World"));
        // window.alert する
        alert("Hello, World");
    }) as Box<dyn Fn()>);

    let el = document().get_element_by_id("foobtn").unwrap();
    let el = el.dyn_ref::<HtmlElement>().unwrap();
    el.set_onclick(Some(cb.as_ref().unchecked_ref()));

    // これをしないと ブラウザコンソールで「Error: closure invoked recursively or destroyed already」と言って怒られる。
    // forget() しておくとメモリに残り続けるらしい。
    cb.forget();
}