ぬの部屋(仮)
nu-no-he-ya
  • 1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
         12
    3456789
    10111213141516
    17181920212223
    2425262728  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
       1234
    567891011
    12131415161718
    19202122232425
    26272829   
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728     
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28      
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
    1234567
    891011121314
    15161718192021
    22232425262728
           
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
         12
    3456789
    10111213141516
    17181920212223
    242526272829 
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
        123
    45678910
    11121314151617
    18192021222324
    25262728   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    15161718192021
    293031    
           
         12
    3456789
    10111213141516
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728     
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
          1
    2345678
    9101112131415
    16171819202122
    232425262728 
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
  • Win32API+WinRT+XamlなGUIを.NETやUWPなしで作成する(1)

    ネイティブからXamlでGUI作成する方法を探した。実装がよくわかってないので内部的には.NETかUWPに依存しているのかもしれない。未確認。少なくともC++17から呼び出すことが可能。

    転載元

    MS公式

    C++ デスクトップ (Win32) アプリで標準 WinRT XAML コントロールをホストする

    https://learn.microsoft.com/ja-jp/windows/apps/desktop/modernize/host-standard-control-with-xaml-islands-cpp

    手順

    WinRTのプロジェクトを作成。ここでUWPが含まれるものを選択しないように注意

    上記からプロジェクトを作るとデフォルトでマニフェストファイルが生成されているので、マニフェストツールから追加のマニフェストファイルに登録する。

    マニフェストファイルの内容を以下のように設定。バージョンはWindows10以降である必要がある。

    <?xml version="1.0" encoding="UTF-8"?>
    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
      <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
        <application>
          <!-- Windows 10 -->
          <maxversiontested Id="10.0.18362.0"/>
          <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
        </application>
      </compatibility>
    </assembly>
    

    続いて、参照を右クリック→参照の追加 を選択。

    C:\Program Files (x86)\Windows Kits\10\UnionMetadata\マニフェストファイルで指定したバージョン\Windows.winmd

    ファイルを追加。

    以下のようにコードを記述。

    #include "pch.h"
    
    #include <windows.h>
    #include <stdlib.h>
    #include <string.h>
    
    #include <winrt/Windows.Foundation.Collections.h>
    #include <winrt/Windows.system.h>
    #include <winrt/windows.ui.xaml.hosting.h>
    #include <windows.ui.xaml.hosting.desktopwindowxamlsource.h>
    #include <winrt/windows.ui.xaml.controls.h>
    #include <winrt/Windows.ui.xaml.media.h>
    
    using namespace winrt;
    using namespace Windows::UI;
    using namespace Windows::UI::Composition;
    using namespace Windows::UI::Xaml::Hosting;
    using namespace Windows::Foundation::Numerics;
    
    
    // Microsoftのサンプルをそのままビルドすると
    // TextOutでリンクエラーが出るのでこれらを追加しておく
    #pragma comment(lib,"gdi32.lib")
    
    
    
    LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM);
    
    HWND _hWnd;
    HWND _childhWnd;
    HINSTANCE _hInstance;


     
    int CALLBACK WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow)
    {
      _hInstance = hInstance;
    
      // The main window class name.
      const wchar_t szWindowClass[] = L"Win32DesktopApp";
      WNDCLASSEX windowClass = { };
    
      windowClass.cbSize = sizeof(WNDCLASSEX);
      windowClass.lpfnWndProc = WindowProc;
      windowClass.hInstance = hInstance;
      windowClass.lpszClassName = szWindowClass;
      windowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    
      windowClass.hIconSm = LoadIcon(windowClass.hInstance, IDI_APPLICATION);
    
      if (RegisterClassEx(&windowClass) == NULL)
      {
        MessageBox(NULL, L"Windows registration failed!", L"Error", NULL);
        return 0;
      }
    
      _hWnd = CreateWindow(
        szWindowClass,
        L"Windows c++ Win32 Desktop App",
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        NULL,
        NULL,
        hInstance,
        NULL
      );
      if (_hWnd == NULL)
      {
        MessageBox(NULL, L"Call to CreateWindow failed!", L"Error", NULL);
        return 0;
      }
    
    
      // Begin XAML Island section.
    
      // The call to winrt::init_apartment initializes COM; by default, in a multithreaded apartment.
      winrt::init_apartment(apartment_type::single_threaded);
    
      // Initialize the XAML framework's core window for the current thread.
      WindowsXamlManager winxamlmanager = WindowsXamlManager::InitializeForCurrentThread();
    
      // This DesktopWindowXamlSource is the object that enables a non-UWP desktop application 
      // to host WinRT XAML controls in any UI element that is associated with a window handle (HWND).
      DesktopWindowXamlSource desktopSource;
    
      // Get handle to the core window.
      auto interop = desktopSource.as<IDesktopWindowXamlSourceNative>();
    
      // Parent the DesktopWindowXamlSource object to the current window.
      check_hresult(interop->AttachToWindow(_hWnd));
    
      // This HWND will be the window handler for the XAML Island: A child window that contains XAML.  
      HWND hWndXamlIsland = nullptr;
    
      // Get the new child window's HWND. 
      interop->get_WindowHandle(&hWndXamlIsland);
    
      // Update the XAML Island window size because initially it is 0,0.
      SetWindowPos(hWndXamlIsland, 0, 200, 100, 800, 200, SWP_SHOWWINDOW);
    
      // Create the XAML content.
      Windows::UI::Xaml::Controls::StackPanel xamlContainer;
      xamlContainer.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() });
    
      Windows::UI::Xaml::Controls::TextBlock tb;
      tb.Text(L"Hello World from Xaml Islands!");
      tb.VerticalAlignment(Windows::UI::Xaml::VerticalAlignment::Center);
      tb.HorizontalAlignment(Windows::UI::Xaml::HorizontalAlignment::Center);
      tb.FontSize(48);
    
      xamlContainer.Children().Append(tb);
      xamlContainer.UpdateLayout();
      desktopSource.Content(xamlContainer);
    
      // End XAML Island section.
    
      ShowWindow(_hWnd, nCmdShow);
      UpdateWindow(_hWnd);
    
      //Message loop:
      MSG msg = { };
      while (GetMessage(&msg, NULL, 0, 0))
      {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
    
      return 0;
    }
    
    
          
    ///////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////
    
    LRESULT CALLBACK WindowProc(HWND hWnd, UINT messageCode, WPARAM wParam, LPARAM lParam)
    {
      PAINTSTRUCT ps;
      HDC hdc;
      wchar_t greeting[] = L"Hello World in Win32!";
      RECT rcClient;
    
      switch (messageCode)
      {
      case WM_PAINT:
        if (hWnd == _hWnd)
        {
          hdc = BeginPaint(hWnd, &ps);
          TextOut(hdc, 300, 5, greeting, wcslen(greeting));
          EndPaint(hWnd, &ps);
        }
        break;
      case WM_DESTROY:
        PostQuitMessage(0);
        break;
    
        // Create main window
      case WM_CREATE:
        _childhWnd = CreateWindowEx(0, L"ChildWClass", NULL, WS_CHILD | WS_BORDER, 0, 0, 0, 0, hWnd, NULL, _hInstance, NULL);
        return 0;
    
        // Main window changed size
      case WM_SIZE:
        // Get the dimensions of the main window's client
        // area, and enumerate the child windows. Pass the
        // dimensions to the child windows during enumeration.
        GetClientRect(hWnd, &rcClient);
        MoveWindow(_childhWnd, 200, 200, 400, 500, TRUE);
        ShowWindow(_childhWnd, SW_SHOW);
    
        return 0;
    
        // Process other messages.
    
      default:
        return DefWindowProc(hWnd, messageCode, wParam, lParam);
        break;
      }
    
      return 0;
    }
    

    実行例

    続く。

    Rustやってみる(10)ライフタイム

    Rustのライフタイムについて。

    まず、多くのプログラミング言語では、「スコープ」という概念がある。

    これは変数の寿命のことで、変数は例えば{}で括られた範囲でしか有効ではない。

    この仕組みはRustにもある。

    #include <iostream>
    
    int main()
    {
      {
        int value = 10;
    
        value = 20;
      }
    
      printf("%d\n", value ); // コンパイルエラー valueはこのスコープに存在しない
    }
    
    fn main( ){
    
      {
        let mut value = 10;
    
        value = 20;
      }
    
      println!("{}",value);// コンパイルエラー valueはこのスコープに存在しない
    
    }
    

    それとは別に、Rustには「ライフタイム」という概念がある。

    ライフタイムは「参照の有効範囲」のことで、C++などでは参照が実は切れていることを、実行時にしか判別できない(下コード左)。

    しかしRustではコンパイルの段階で明らかに参照が切れているような状態を検出できる(下コード右)ので、参照が切れるようなコードはそもそもコンパイルが通らず、実行すること自体ができない。

    故にRustでは「ビルドが通ったなら安易な参照切れは起こしていない」と言える。

    #include <iostream>
    
    struct AB {
      int a, b;
    };
    
    int main()
    {
      auto myref = std::make_unique<AB>(AB{ 5,10 });
    
      {
        auto ab = std::move(myref); // ここで myrefからabへmove
    
        printf("%d\n", ab->a);
      }
    
      // 実行時エラー 参照先が無効
      auto k = myref->a;
    
      printf("%d\n", k);
    }
    
    struct AB{
      a:i32,
      b:i32,
    }
    //////////////////////////////////////////////////
    fn main( ){
    
      let myref=AB{a:5,b:10};
      {
    
        let ab=myref; // ここで myrefからabへmove
    
        println!("{}",ab.a);
    
      }
    
      // コンパイルエラー 参照先が無効
      let k = myref.a;
    
      println!("{}",k);
    
    }
    

    Rustやってみる(9)関数でGenericsを使ってみる

    1.自分で実装する場合

    まず以下のように定義する。

    struct IntValue      ... TraitMyDisp と TraitMyPow 実装

    struct FloatValue  ... TraitMyPow のみ実装

    // これをimplementしているときは表示できる
    trait TraitMyDisp{
      fn disp(&self);
    }
    
    // これをimplementしているときは値を二乗する
    trait TraitMyPow{
      fn get_pow2(&self)->f32;
    }
    
    //////////////////////////////////////////
    //////////////////////////////////////////
    
    struct IntValue{ value: i32 }
    
    impl TraitMyDisp for IntValue{
      fn disp(&self){
        println!("{}",self.value);
      }
    }
    impl TraitMyPow for IntValue{
      fn get_pow2(&self)->f32{
        ( self.value*self.value ) as f32
      }
    }
    //////////////////////////////////////////
    //////////////////////////////////////////
    
    struct FloatValue{ value:f32 }
    
    impl TraitMyPow for FloatValue{
      fn get_pow2(&self)->f32{
        ( self.value*self.value ) as f32
      }
    }
    

    例1

    失敗例1

    まず、以下のようにただ<T>を渡してもコンパイルは通らない。

    // C++だと T に get_pos2があればビルドが通るが
    // Rustでは valueに対して何をできるのかを指定しなければならない
    fn call<T>(value:T){
      println!("call {}",value.get_pow2()); // NG   T にget_pow2が必要なんて聞いてない 
    }
    

    fn main(){ // TraitMyDisp , TraitMyPow の両方が実装済み let i_val = IntValue{value:2}; // TraitMyPow のみが実装済み let f_val = FloatValue{value:2.0}; call(i_val); }

    修正1

    「型Tを取る」ではなく、「get_pow2()を持つ型Tを取る」と記述しなければいけない。

    // T は TraitMyPow を実装していなければならない
    fn call< T : TraitMyPow >(value:T){
      println!("call {}",value.get_pow2());
    }
    

    例2

    トレイトは + で複数指定できる。

    T は+で指定されたすべてのトレイトに対応していなければならない。

    たとえその関数の中で使っていなくても、実装だけはしていなければならない。

    // <T:トレイト + トレイト> のように+で複数指定できる 
    fn call_both<T:TraitMyPow + TraitMyDisp>(value:&T){
    
      // TraitMyDisp::dispは使っていないが、トレイト境界を指定しているので
      // Tがdispに対応していないならコンパイルできない(たとえ使っていなくても)
      println!("call {}",value.get_pow2());
    }
    
    
    fn main(){
    
      // TraitMyDisp , TraitMyPow の両方が実装済み
      let i_val = IntValue{value:2};
    
      // TraitMyPow のみが実装済み
      let f_val = FloatValue{value:2.0};
    
      call_both(&i_val); // OK
      // call_both(&f_val); // NG FloatValueのためのTraitMyDispはimplしていない
    
    }
    

    2.operatorを使用可能にする

    Tに渡される型が + 演算できるかどうかはわからない。

    したがって、例え自分がプリミティブな数値型しか与えるつもりがなくても、コンパイラはそんなことは知らないので「TはAddが可能である」ことを教えなければいけない。

    // Addモジュールを使う
    use std::ops::Add;
    
    /////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////
    
    
    // add関数の定義
    // Tの必須の振る舞いとしてAddを指定。これで operator + が使える
    fn add< T : Add<Output=T> >( v1:T , v2:T ) -> T
    {
      
    v1 + v2
    
    }
    fn main(){
    
      let val:i32 = add( 3,4);
    
    }
    

    Rustやってみる(8) traitでポリモーフィズムを書いてみる

    Rustには継承はないがポリモーフィズムはある。C++やJavaのようなオブジェクト指向ではポリモーフィズムの実現のために継承があるようなイメージがあるので、この関係が奇妙に見える。

    継承とは「鷹も燕も"鳥"の特性をすべて持ち、その他に若干の差異がある同種のモノである」という考え方をする。だからどうしても子クラスが肥大化していく。そのあたりを嫌った結果らしい。

    // 振る舞い
    trait Flying{
      fn fly(&self);
    }
    

    // 構造体 鷹
    struct Hawk{
      weight:f32,
      speed:f32,
    }
    
    // トレイトのR実装
    impl Flying for Hawk{
    
      // メソッド 
      fn fly(&self){
        println!("鷹が飛ぶ {} km/h \n",self.speed );
      }
    
    }
    

    // 構造体 ハチドリ
    struct Hummingbird{
      weight:f32,
      speed:f32,
    }
    
    // トレイトのR実装
    impl Flying for Hummingbird{
      // メソッド 
      fn fly(&self){
        println!("ハチドリが飛ぶ {} km/h\n", self.speed);
      }
    }
    

    fn main() {
      
      // スタック上に確保する固定長配列は [T;N]の形をしている
      // T ... Type , N ... 個数
      let ary:[ Box<dyn Flying> ; 2 ] =
      [
        // Boxはヒープにメモリを確保する。
        Box::new(Hawk{weight:1100.0,speed:190.0}), // アカオノスリ
        Box::new(Hummingbird{weight:20.0,speed:98.0}) // ハチドリ
      ];
    
      ary[0].fly();
      ary[1].fly();
    
    }
    

    C++の継承が「Birdの特性を持った鷹を実装」という形であるのに対し、

    Rustのtraitは「Flyという振る舞いを、鷹や燕の特性に付与する」というような発想をすると、現時点ではとらえている(下図、現時点の解釈

    C++のオブジェクト指向だと飛べないはずのペンギンもflyを持たざるを得ないが、Rustのtraitであればペンギンにはflyを付与しなければよいだけの話だということになる。

    Rustやってみる(7) 配列を使ってみる

    配列にはいくつか種類があるらしい。

    ・[T;N] ... スタック上に固定長配列

    ・Vec<T> ヒープ上の可変長配列

    ・Box<[T;N]>ヒープ上に固定長配列

    注意点として、基本的に配列の要素は全て初期化しなければならない。可変長配列でcapacityを指定できるVecはともかく、それ以外をメモリ確保だけして初期化したくない場合には、std::mem::MaybeUninitを使わなければならない。これはunsafeで囲まなければならない。

    fn main() {
    
      ////////////////////////////////////////////
      // 固定長配列(スタック)
    
      let mut ary1:[i32;5]=[1,2,3,4,5];
    
      for a1 in ary1{
        print!("{} ",a1);
      }
      println!("");

      // 初期化しないバージョン
      let mut ary2:[i32;5]  = unsafe { std::mem::MaybeUninit::uninit().assume_init() };
      for a2 in ary2{
        println!("* {} ",a2);
      }
      println!("\n");
    

    //////////////////////////////////////////// // 可変長配列
      let mut vec1:Vec<&str> = vec!["a", "b", "c"];
      vec1.push("d");
      for v1 in vec1{
        print!("{} ",v1);
      }
      println!("");

      // 初期化しないバージョン
      let mut vec2:Vec<&str> = vec![];
      vec2.push("d");
      for v2 in vec2{
        print!("* {} ",v2);
      }
      println!("\n");

      ////////////////////////////////////////////
      // 固定長配列(ヒープ)
    
      let mut box1:Box<[f32;5]> = Box::new([10.5 , 11.5 , 12.5 , 13.5 , 14.5]);
      for b1 in box1.iter(){
        print!("{} ",b1);
      }
      println!("");

      // 初期化しないバージョン
      let mut box2:Box<[f32;5]> = Box::new(unsafe { std::mem::MaybeUninit::uninit().assume_init() } );
      for b2 in box2.iter(){
        println!("* {} ",b2);
      }
    }
    

    実行例

    初期化しなければ不正な値が入っていることを確認できた。

     

    1 2 3 4 5
    * 112
    * 0
    * -580595040
    * 367
    * -580614544


    a b c d
    * d

    10.5 11.5 12.5 13.5 14.5
    * 2
    * 0
    * -1030514000000000000
    * 0.000000000000000000000000000000000000000000514
    * 0.000000000000000000000000000000000000000000006

     

    Rustやってみる(6)struct , impl , trait

    構造体関連で、struct,impl,trait の役割は以下(だと考えられる)

    • struct ... 構造体を定義
    • impl ... メソッドを定義
    • trait ... structのメソッドに制約をつける

    本当はポリモーフィズムをやりたかったがどうしても理解が追い付かなかったので省略。

    構造体の定義とインスタンス生成

    // #[derive(Debug)] をつけるとprintln!でそのまま表示できるようになる
    #[derive(Debug)]
    // 構造体の定義。
    struct Rectangle{
      width:i32,
      height:i32,
    }
    
          
    fn main() {
      
      // 初期化なしでは定義できない
      //let mut rr = Rectangle{};  
      let mut rr = Rectangle{width:0,height:0};
    
      // mut をつけているので代入できる
      rr.width = 20;
      rr.height = 20;
    
      // #[derive(Debug)] をつけているので {:?} で表示できる
      println!("{:?}",rr);
    
    }
    

    構造体にメソッドを定義

    // 構造体の定義
    struct Rectangle{
      width:i32,
      height:i32,
    }
    
    // implの中でメソッドや関連関数を定義 impl Rectangle{ // Rectangleのメソッドを定義 メソッドはselfをとる。 selfがないなら関連関数 fn area(&self)->i32{ return self.width * self.height; } }
    fn main() {
      
      // インスタンス生成
      let mut rr = Rectangle{width:0,height:0};
    
      rr.width = 20;
      rr.height = 20;
    
      // メソッド呼び出し 
      println!("{}",rr.area() );
    
    }
    

    構造体に関連関数を定義

    implの中に&selfをとらない関数を定義すると関連関数になる。

    新規インスタンスを作成する関連関数を定義する場合、名前をnewにするのが一般的らしい。

    呼び出しは 構造体名::関連関数名() となる。

    // 構造体の定義
    struct Rectangle{
      width:i32,
      height:i32,
    }
    
    impl Rectangle{
    
      // 関連関数。 &selfをとらない。
      // Rectangle::new で呼び出す。
      // 新規インスタンス生成関連関数は「new」にする習慣がある
      fn new()->Rectangle{
    
        return Rectangle{width:20,height:30};
    
      }
    
      // メソッド
      fn area(&self)->i32{return self.width * self.height;}
    
    }
    

    fn main() {
      
      // 関連関数でインスタンス生成
      let mut rr = Rectangle::new();
    
      println!("{}",rr.area() );
    
    }
    

    traitで振る舞いを定義

    implをbehavior_calc_areaの実装とすることで、areaメソッドの実装を強制することができる。

    // 振舞いの定義
    trait behavior_calc_area{
      fn area(&self)->f32;
    }
    

    // 構造体の定義
    struct Rectangle{
      width:i32,
      height:i32,
    }
    
    // トレイトのR実装
    impl behavior_calc_area for Rectangle{
    
      // メソッド 
      fn area(&self)->f32{
        return (self.width * self.height) as f32;
      }
    
    }
    

    struct Triangle{
      width:i32,
      height:i32,
    }
    
    // トレイトのR実装
    impl behavior_calc_area for Triangle{
      // メソッド 
      fn area(&self)->f32{
        return (self.width * self.height) as f32 / 2.0 ;
      }
    }
    
    fn main() {
      
      // インスタンス生成
      let t:Triangle = Triangle{width:10,height:5};
      let r:Rectangle = Rectangle{width:10,height:5};
    
      println!("{}\n",t.area() );
      println!("{}\n",r.area() );
    
    }
    

    Rustやってみる(5)関数を定義・呼び出し

    基本はそんなに複雑ではないのだが、呼び出すときに暗黙型変換してくれないらしく、明示的型変換(as f32) を入れないといけないらしい。

    // 関数定義
    // 値渡し
    fn add(a:f32,b:f32)->f32{
      return a+b;
    }
    
    fn main()  {
    
      // 関数呼び出し
      // 引数に整数を入れてもaddのf32に暗黙変換できないらしいので
      // as f32 で実数に型変換する
      let k = add(3 as f32,5 as f32);
    
      println!("k= {}",k);
    
    }
    

    不変参照で渡すときは渡す側と受ける側で&をつける。

    // デフォルトで不変参照。C++でいうところのconst。kの内容を変更できない
    fn add2(k: &i32)->f64{
    
      // &mutでないときは *k としなくていいらしい
      return (k + 2) as f64;
    }
    

    fn main() { let a:i32=3; // mutがついていないので変更不可 println!(" {}", add2(&a) ); // aの定義時にmutをつけていないのでここもただの& }

    可変参照は型名の前に&mut をつける。

    呼び出す側でも&mutが必要。

    さらにこの値を使うときは参照外しとして*をつけなければならない。もっとほかの記号はなかったのか。

    // &mut で可変参照
    fn swap(i:&mut i32,j:&mut i32){
      let k:i32;
    
      // &mutの時は頭に*をつけて *i とする
      k = *i;
      *i = *j;
      *j = k;
    }
    
    fn main() {
      let mut a:i32=3;
      let mut b:i32=8;
      swap(&mut a,&mut b);
      println!("{} {}",a,b);
    }
    

    genericsをやりたいが。

    C++のテンプレートのようなgenericsという機能があるが、ただ<T>としただけでは動かない。printlnすらできない。いずれ詳しく調べる。

    https://www.koderhq.com/tutorial/rust/generics/

    use std::ops::Mul;
    fn square<T: Mul<Output = T> + Copy >(val:T)->T{
    
      return val*val;
    
    }
    
          
    
    use std::fmt::Display;
    fn console_log<T: Display> (x: T) {  
    
      println!("{}", x);
    
    }
    
    fn main() {
      
      println!("{}",  square(3) );
    
      console_log( 3 );
    
    }
    

    Rustやってみる(4)分岐や反復など

    ループ

    fn main() {
      for x in 1..=9{
        for y in 1..=9{
            print!("{} ",x*y);
        }
        println!("");
      }
    }
    
    1 2 3 4 5 6 7 8 9
    2 4 6 8 10 12 14 16 18
    3 6 9 12 15 18 21 24 27
    4 8 12 16 20 24 28 32 36
    5 10 15 20 25 30 35 40 45
    6 12 18 24 30 36 42 48 54
    7 14 21 28 35 42 49 56 63
    8 16 24 32 40 48 56 64 72
    9 18 27 36 45 54 63 72 81

    なんとRustのforにはCのforのようにカウンタを使う記述法がない。その手のものが必要な時はwhileを使う。さらにRustにはインクリメント演算子++がない。+=はあるのでそれを使う。

    なぜ++がないのかよくわからないが、コンパイラが進化した今inc命令とadd命令をプログラマが区別する必要はないのでそのために言語仕様を複雑にする必要はないとかそんな感じではないだろうか(適当)。

    fn main() {
      let mut k = 0;// 変数はデフォルトで変更不可なのでmutをつける
      while k < 10{
        println!("k=={}",k);
        k+=1; // Rustには++がない
      }
    
    }
    

    分岐

    if

    ifはCとかなり近い。ただし()で囲う必要がない。

    fn main()  {
    
      let k = 3;
    
      if k == 1{
        println!("k==1");
      }
      else if k==2{
        println!("k==2");
      }
      else{
        println!("other k");
      }
    
    }
    

    特に違うものとして、Cの三項演算子に該当するものがifで表記するようになっている。

    fn main()  {
    
      let k = 2;
    
      let msg = if k%2!=0 {"odd"}else{"even"};
     
      println!("{}",msg);
     
    }
    

    match

    いろいろとCのswitchに近いがbreakしないところが特に違う。あとカンマ区切り。

    fn main()  {
    
      let i = 2;
    
      // switchに近い。
      // ただし、matchの中で、「取りうるすべての可能性について」処理する必要がある
      match i{
    
        // Cと違いbreakしなくてもいい。ほかの式が実行されることはない
        3 => println!("three"),
    
        // 複数の指揮を実行するときは{}で括る
        4 => {
          println!("four");
          println!("FOUR")
        },
    
        // 取りうるすべての可能性を記述しなければいけないため
        // ワイルドカード _ を使ってCのdefaultと同じことをする。
        _ => println!("others"),
      };
     
    }
    

    matchの結果をそのまま変数に渡すこともできる。

    fn main()  {
    
      let i = 3;
    
      let msg:&str =   match i{
    
        3 => "three",
    
        4 => "four",
    
        _ => "others",
      };
    
      println!("{}",msg);
    
    }
    

    Rustやってみる(3)標準入力・ファイル入出力・あと文字列→数値

    キーボード入力

    // 入出力を使う
    use std::io;
    
    fn main() {
    
      // 変数 buffer を定義
      let mut buffer = String::new();
    
      // bufferへ文字列入力
      io::stdin().read_line(&mut buffer);
    
      // bufferを表示
      println!("{}",buffer);
    
    }
    

    文字列→数値

    // 入出力を使う
    use std::io;
    
    fn main() {
    
      // 変数 buffer を定義
      let mut buffer = String::new();
    
      io::stdin().read_line(&mut buffer); //標準入力から入力
    
      // 型指定 :i32 が必要
      // read_lineから読み込んだ文字列に対してはtrim()が必要
      let val:i32 = buffer.trim().parse().unwrap();
    
      // bufferを表示
      println!("{}",val);
    
    }
    

    ファイル入力

    // ファイル入力を使う
    use std::{fs::File, io::Read};
    
    fn main() {
    
      let filename = "test.txt";
     
    // ファイル入力を使う let mut file = File::open(filename).expect("file not found"); // 変数 buffer を定義 let mut buffer = String::new(); // ファイルから入力 file.read_to_string(&mut buffer).expect("something went wrong reading the file"); // ファイルを閉じる方法 // 方法1 スコープを抜けるとdropが呼ばれる(C++のデストラクタのようなもの) // 方法2 明示的にdropを呼び出す drop(file); // 明示的にdropを呼び出す // bufferを表示 println!("{}",buffer); }

    ファイル出力

    use std::fs::File;
    
    // write!やwrite_allを使うのに必要
    use std::io::Write;
    
    // 戻り値は std::io::Result<()> 型
    // 最後に OK(()) を返す。
    // これを入れないとwrite_allなどが使えない
    fn main()-> std::io::Result<()> {
    
      let filename = "test.txt";
     
      // ファイル入力を使う
      let mut file = File::create(filename)?;
      // 末尾の ? は例外処理のようなもの関連
      // ただしRustには例外がないのであくまでそれっぽく振る舞うだけ。
    
      // 変数 buffer を定義
      let _buffer = "hello".to_string();
    
      // ファイルへ書き出し
      file.write_all(_buffer.as_bytes())?;
    
      // こっちも使える
      // write!(file,"hello2")?;
    
      // ファイルを閉じる
      drop(file);
    
      // std::io::Result<()> 型の場合
      Ok(())
    
    }
    

    Rustやってみる(2)cargoコマンド

    Cargo

    CargoはRustのビルドシステム及びパッケージマネージャ。

    新規プロジェクト作成

    cargo new myproj

    ビルド

    cargo buildはカレントディレクトリにsrcディレクトリがあることを想定する。

    デバッグビルド

    cargo build

    リリースビルド

    cargo build --release

    パッケージを使う

    Rustではパッケージのことを「クレート」というらしい。Cargo.tomlの[dependencies]にモジュール名とバージョンを記述する。

    [package]
    name = "myproj"
    version = "0.1.0"
    edition = "2021"

    [dependencies]
    regex = "1.6.0"

    use regex::Regex;
    
    fn main() {
        let re = Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
        println!("Did our date match? {}", re.is_match("2014-01-01"));
    }
    
    cargo build

    cargo buildすると勝手にcrates.ioからクレートを取得するので上記の記述以外にすることはない。

    デバッグ(VSCode)

    VSCodeでデバッグできるのだが、私の環境では、クレートを使っているとVSCode関連で失敗する。

    細かく検証していないが上記regexを使った場合VSCodeからは実行すらできない。PowerShellからは動く。

    Error: Os { code: 10061, kind: ConnectionRefused, message: "対象のコンピューターによって拒否され
    たため、接続できませんでした。" }

    どれだけ検索しても対策が見つからなかったがcodelldbのバージョンによっては起こる?らしい。