RSS リーダー チュートリアル (VS Code を使用した Windows 用 Rust)

前のトピックでは、Windows 用 Rust と windows クレートについて紹介しました。

ここでは、Really Simple Syndication (RSS) フィードからブログ投稿のタイトルをダウンロードする単純なコンソール アプリを記述することで、Windows 用 Rust を試してみましょう。

  1. コマンド プロンプト (cmd.exe) を起動し、Rust プロジェクトを保持するフォルダーに cd で移動します。

  2. Cargo を使用して rss_reader という名前の新しい Rust プロジェクトを作成し、作成されたフォルダーに cd で移動します。

    > cargo new rss_reader
    >     Created binary (application) `rss_reader` package
    > cd rss_reader
    
  3. 次に、VS Code で rss_reader プロジェクトを開きます。

    code .
    
  4. メインの rss_reader プロジェクトを実装しましょう。 まず、プロジェクトのルートにある Cargo.toml ファイルを開きます。 Cargo.toml ファイルは、Rust プロジェクトを、そこにあるすべての依存関係を含めて記述しているテキスト ファイルです。

    次の一覧に示すように、windows クレートに依存関係を追加します。 windows クレートは大きいです。 ビルド時間を短縮するために、このコードに必要な Foundation_CollectionsWeb_Syndication 機能のみを選択します。

    # Cargo.toml
    ...
    
    [dependencies.windows] 
    version = "0.43.0"
    features = [
        "Foundation_Collections",
        "Web_Syndication",
    ]
    
  5. 次に、rss_reader プロジェクトの src/main.rs ソース コード ファイルを開きます。 そこに、Cargo の既定の "Hello, world!" コードがあります。 main.rs の先頭に次の use ステートメントを追加します。

    // src\main.rs
    use windows::{
        core::*,
        Foundation::Uri,
        Web::Syndication::SyndicationClient
    };
    
    fn main() {
        println!("Hello, world!");
    }
    

    use 宣言によって、使用する型へのパスが短縮されます。 前に触れた Uri 型があります。

  6. 新しい Uri を作成するために、Cargo の既定の main 関数を次のように置き換えます。

    // src\main.rs
    ...
    
    fn main() -> Result<()> {
        let uri = Uri::CreateUri(h!("https://blogs.windows.com/feed"))?;
    
        Ok(())
    }
    

    main 関数の戻り値の型が windows::core:: からの Result であることに注意してください。 オペレーティング システム (OS) API からのエラーを処理するのは一般的であるため、これによって処理がより容易になります。 windows::core::Result は、エラーの伝達と簡潔なエラー処理に役立ちます。

    コード行の末尾に、疑問符の演算子があることがわかります。 入力量を減らすため、これにより Rust のエラー伝達と短絡論理を利用しています。 これは、この簡単な例では、手動のエラー処理を多数行う必要がないことを意味します。 Rust のこの機能の詳細については、「より簡単なエラー処理のための ? 演算子」を参照してください。

    また、windows クレートの h! マクロにも注目してください。 これを使用して、Rust 文字列リテラルから HSTRING 参照を作成しています。 WinRT API では、文字列値に HSTRING を広範囲に使用します。

  7. RSS フィードをダウンロードするために、新しい SyndicationClient を作成します。

    // src\main.rs
    ...
    
    fn main() -> windows::core::Result<()> {
        let uri = Uri::CreateUri(h!("https://blogs.windows.com/feed"))?;
        let client = SyndicationClient::new()?;
    
        Ok(())
    }
    

    new 関数は Rust コンストラクターです。 windows クレート内のすべてのオブジェクトは Rust 規則に従い、コンストラクターに new という名前を付けます。

  8. これで、SyndicationClient を使用してフィードを取得できます。

    // src\main.rs
    ...
    
    fn main() -> windows::core::Result<()> {
        let uri = Uri::CreateUri(h!("https://blogs.windows.com/feed"))?;
        let client = SyndicationClient::new()?;
        let feed = client.RetrieveFeedAsync(&uri)?.get()?;
    
        Ok(())
    }
    

    RetrieveFeedAsync は非同期 API であるため、ブロックする get 関数を使用してサンプルを単純にしています。 代わりに、async 関数内で await 演算子を使用して、結果を協調的に待機することもできます。 グラフィカル ユーザー インターフェイスを備えたより複雑なアプリでは、async が頻繁に使用されます。

  9. これで、結果として得られる項目を反復処理できるので、タイトルだけを出力しましょう。 一部の RSS フィードで必要なため、user-agent ヘッダーを設定するための追加のコード行も以下に示されています。

    // src\main.rs
    ...
    
    fn main() -> windows::core::Result<()> {
        let uri = Uri::CreateUri(h!("https://blogs.windows.com/feed"))?;
        let client = SyndicationClient::new()?;
    
        client.SetRequestHeader(
            h!("User-Agent"),
            h!("Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)"),
        )?;
    
        let feed = client.RetrieveFeedAsync(&uri)?.get()?;
    
        for item in feed.Items()? {
            println!("{}", item.Title()?.Text()?);
        }
    
        Ok(())
    }
    
  10. ここでは、 [実行]>[デバッグなしで実行] をクリックして (または Ctrl + F5 キーを押して)、ビルドと実行が可能であることを確認しましょう。 予期しないメッセージが表示された場合は、「Hello, world! チュートリアル (VS Code を使用した Rust)」を正常に完了したことを確認してください。

    テキスト エディター内にも [デバッグ][実行] のコマンドが埋め込まれています。 または、rss_reader フォルダー内のコマンド プロンプトから「cargo run」と入力します。これにより、プログラムがビルドされて実行されます。

    The Debug and Run commands embedded in the text editor

    VS Code の [ターミナル] ペインの下方では、Cargo によって、windows クレートのダウンロードとコンパイルが正常に行われ、結果がキャッシュされて、それを使用して後続のビルドがより短い時間で完了したことを確認できます。 その後サンプルをビルドして実行し、ブログ投稿のタイトルの一覧を表示しています。

    List of blog post titles

Windows のために Rust をプログラミングすることは、これほど簡単です。 ただし内部的には、Rust で ECMA-335 (共通言語基盤すなわち CLI) に基づく .winmd ファイルを解析すること、および安全性と効率性の両方を考慮に入れて実行時に COM ベースのアプリケーション バイナリ インターフェイス (ABI) を忠実に遵守することの両方が可能なように、ツールの構築に多くの労力が注がれています。

メッセージ ボックスの表示

Windows 用 Rust では、任意の Windows API (過去、現在、将来) を呼び出すことができることは説明しました。 そこで、このセクションでは、いくつかの Windows メッセージ ボックスを紹介します。

  1. RSS プロジェクトの場合と同じように、コマンド プロンプトで Rust プロジェクトを含むフォルダーに cd で移動します。

  2. message_box という名前の新しいプロジェクトを作成し、VS Code で開きます。

    > cargo new message_box
    >     Created binary (application) `message_box` package
    > cd message_box
    > code .
    
  3. VS Code で Cargo.toml を開き、このプロジェクトの Windows 依存関係を追加します。

     # message_box\Cargo.toml
     ...
    
     [dependencies.windows]
     version = "0.43.0"
     features = [
         "Win32_Foundation",
         "Win32_UI_WindowsAndMessaging",
     ]
    
  4. 次に、プロジェクトの src/main.rs ファイルを開き、新しい名前空間を使用して use 宣言を追加します (下に示すように)。 最後に、MessageBoxAMessageBoxW 関数を呼び出すコードを追加します。 Windows API のドキュメントは主に C/C++ を念頭に置いて記述されているため、API ドキュメントを windows クレート内の Rust プロジェクションのドキュメント (MessageBoxA (Rust)MessageBoxW (Rust)) と比較すると便利です。

    // src\main.rs
    use windows::{
        core::*,
        Win32::UI::WindowsAndMessaging::*
    };
    
    fn main() {
        unsafe {
            MessageBoxA(None, s!("Ansi"), s!("World"), MB_OK);
            MessageBoxW(None, w!("Wide"), w!("World"), MB_OK);
        }
    }
    

    見てのとおり、これらの Win32 API を unsafe ブロック内で 使用する必要があります (「unsafe ブロック」を参照)。 また、Rust UTF-8 文字列リテラルから LPCSTR 引数と LPCWSTR 引数を作成する s! マクロと w! マクロにも注意してください。これは h! マクロを使用して rss_readerHSTRING を作成したのとほぼ同じです。 Rust は UTF-8 文字列を使用するネイティブ Unicode であるため、ANSI (A サフィックス) API よりもワイド Unicode (W サフィックス) Windows API を使用することをお勧めします。 これは、コードで英語以外のテキストを使用する場合に重要になることがあります。

今度はビルドして実行すると、Rust により 2 つの Windows メッセージ ボックスが表示されます。