PyramidでToDo管理サービスを作る 【ToDo登録画面作成】

前回は、ToDoを管理するモデルを作成したので、登録するための画面を作成する。
# 前回からだいぶ時間が経ってしまった…

neoinal.hatenablog.com

実行環境

セッションの設定

pyramidでセッションを使うには、 config に使用するセッションを登録すれば良いらしい。

todomanager/__init__.py にセッションを使うための設定をする。
セッションのシークレットキーは外部ファイルや環境変数辺りに設定するのが正しいのだろうけど、まだ作り途中であるため development.ini から読み取るようにする。

import hashlib
from pyramid.session import SignedCookieSessionFactory

def main(global_config, **settings):
    secret = hashlib.sha256(str(settings['pyramid.session.secret']).encode('utf-8')).hexdigest()
    session_factory = SignedCookieSessionFactory(secret=secret)
    # 省略
    config.set_session_factory(session_factory)

development.ini にシークレットキーを設定する。
デプロイするときはランダム生成させた文字列にした方が良いと思われる。

pyramid.session.secret = development

テンプレートの設定

pyramidのデフォルトで設定されているテンプレートエンジンは Chameleon となっている。
Djangoでは標準のテンプレートを使っていたことも有り、 jinja2 に変更する。

テンプレートエンジン用のモジュールをインストール

次のコマンドを入力してモジュールをインストールする。

(pyramid_python)> pip install pyramid_jinja2

レンダラーを変更

Jinja2 を利用して作成したテンプレートを表示するための準備を行う。
ToDoManager を起動させる上で必要となるモジュール郡の中に、テンプレートエンジン用のモジュールが設定されているので、その部分を Jinja2 用に変える。

setup.py に書かれている部分を次のように修正する。

requires = [
    ...
    'pyramid_chameleon',
    ...
    ]
↓
requires = [
    ...
    'pyramid_jinja2',
    ...
    ]

MANIFEST.in に書かれている以下の部分に *.jinja2 を追記する。

recursive-include todomanager *.ico *.png *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml *.jinja2
                                                                                                      ^^^^^^^^

todomanager/__init__.py に書かれている部分をつぎのように修正する。

def main(global_config, **settings):
    ...
    config.include('pyramid_chameleon')
    ...
↓
def main(global_config, **settings):
    ...
    config.include('pyramid_jinja2')
    ...

テンプレートの作成

テンプレートエンジンとして jinja2 を使用するが、タグや記述方法については公式を参照。

Welcome to Jinja2 — Jinja2 Documentation (2.8-dev)

Bootstrapの用意

こういうサービスを作るときに便利なのが Bootstrap である。

Bootstrap · The world's most popular mobile-first and responsive front-end framework.

「Bootstrap CDN」を利用すると、必要なファイル一式をダウンロードしなくてもBootstrapを使うことができるらしい。
今回は、静的ファイルの使い方を練習する意味も兼ねてBootstrap一式をダウンロードすることにした。

ToDoManager/todomanager/staticbootstrap ディレクトリを作成して、展開したファイル一式をコピーする。

./ToDoManager/todomanager/static
└─bootstrap
    ├─css
    │      bootstrap-theme.css
    │      bootstrap-theme.css.map
    │      bootstrap-theme.min.css
    │      bootstrap.css
    │      bootstrap.css.map
    │      bootstrap.min.css
    │
    ├─fonts
    │      glyphicons-halflings-regular.eot
    │      glyphicons-halflings-regular.svg
    │      glyphicons-halflings-regular.ttf
    │      glyphicons-halflings-regular.woff
    │      glyphicons-halflings-regular.woff2
    │
    └─js
            bootstrap.js
            bootstrap.min.js
            npm.js

テンプレートの共通部分

それぞれのページで共通となる部分を base.jinja2 と定義して以下の様に記述する。

{%- set navigation_bar = [
    (request.route_url('home'), 'home', 'Home'),
    (request.route_url('create'), 'create', 'Create'),
] -%}
{%- set active_page = active_page|default('home') -%}
<!DOCTYPE html>
<html lang="{{ LANGUAGE_CODE|default('ja') }}">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>{{ page_title|default('ToDo Manager') }}</title>
    <link href="./static/bootstrap/css/bootstrap.min.css" rel="stylesheet">
    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
    <script src="./static/bootstrap/js/bootstrap.min.js"></script>
</head>
<body>
    <nav class="navbar navbar-inverse navbar-static-top">
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="{{ request.route_url('home') }}">ToDo Manager</a>
        </div>
        <div id="navbar" class="collapse navbar-collapse">
          <ul class="nav navbar-nav">
          {%- for here, id, caption in navigation_bar %}
              <li{% if id == active_page %} class="active"{% endif %}><a href="{{ here|e }}">{{ caption|e }}</a></li>
          {%- endfor %}
          </ul>
        </div><!--/.nav-collapse -->
      </div>
    </nav>
    <div class="container-fluid">
    {%- block container %}{%- endblock %}
    </div><!-- /.container-fluid -->
</body>
</html>

ToDoを登録するページを create.jinja2 として以下のように記述する。

{% extends 'base.jinja2' %}

{%- block container %}
<div class="row">
    <form name="create" action="{{ request.route_url('create') }}" method="post" class="form-horizontal col-md-8 col-md-offset-2">
        <input type="hidden" name="csrf_token" value="{{ request.session.get_csrf_token() }}" />
    {%- if result != null %}
        <div class="alert{% if result['status'] == 'success' %} alert-success{% else %} alert-danger{% endif %}" id="result-alert" role="alert">
            <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden>&times;</span></button>
            {{ result['message']|e }}
        </div>
    {%- endif %}
        <div class="form-group">
            <label class="control-label" for="id_summary">ToDo 内容</label>
            <textarea id="id_summary" name="summary" class="form-control" rows="10" cols="40" required="required"></textarea>
        </div>
        <div class="form-group">
            <button class="btn btn-success" type="submit">登録</button>
        </div>
    </form>
</div>
{%- endblock %}

ビューの設定

ビューの処理を作成

scaffoldで作成された view.py は、クラスは無く関数にURLのマッピングレンダリング用のテンプレートが指定されている。

from pyramid.response import Response
from pyramid.view import view_config

@view_config(route_name='home', renderer='templates/mytemplate.pt')
def my_view(request):
    return Response("This page does not created yet.", content_type='text/plain', status_int=500)

機能毎にビューを分けられるようクラスを使用して、マッピングするURLとレンダリング用のテンプレートの設定などを行う。
ホームの処理については、画面デザインを決めあぐねているため仮置きとする。

from pyramid.response import Response
from pyramid.session import check_csrf_token
from pyramid.view import view_config
from todomanager.models import Task, DBSession


class TaskView(object):

    def __init__(self, request):
        self.request = request

    @view_config(route_name='home', renderer='templates/base.jinja2')
    def home(self):
        return Response(
            "This page does not created yet.",
            content_type='text/plain',
            status_int=500
        )

    @view_config(route_name='create', renderer='templates/create.jinja2')
    def create(self):
        parameter = {
            "page_title": "ToDo Manager - タスクの作成",
            "active_page": "create",
        }

        if self.request.method == 'POST':
            if check_csrf_token(self.request):
                summary = self.request.POST.get("summary")
                if summary is not None:
                    task = Task(summary=summary)
                    DBSession.add(task)
                    result = {
                        "status": "success",
                        "message": "ToDoの登録に成功しました。",
                    }
                else:
                    result = {
                        "status": "error",
                        "message": "内容が入力されていません。",
                    }

                parameter["result"] = result
            else:
                raise ValueError("CSRF token did not match.")
        return parameter

ビューを表示するところに、ToDoをDBに登録する処理があるのはイケてない感じがするものの、ひとまずはこれで登録できるようになった。

URLとマッピング

作成したビューの処理を呼び出すために todomanager/__init__.py にルーティングを設定する。
今回新たに紐付けたURLは以下の1つ。

  • ToDo作成画面(/create)

もともと設定されていた home はそのまま使用する。

def main(global_config, **settings):
    ...
    config.add_route('home', '/')
    config.add_route('create', '/create')
    ...

PyramidでToDo管理サービスを作る 【DBマイグレーション】

データベースを使用するためのプロジェクトもできたことだし、これからToDo管理サービスで使うモデルを作成していこうと思う。

実行環境

モデルを作る

ToDoManager/todomanager/models.py にscaffold時に作成されたデフォルトのモデルが設定されている。

class MyModel(Base):
    __tablename__ = 'models'
    id = Column(Integer, primary_key=True)
    name = Column(Text)
    value = Column(Integer)

Index('my_index', MyModel.name, unique=True, mysql_length=255)

今回は不要なので削除しつつ、必要となるモデルを追加していく。
取り敢えずユーザ情報とかは後回しにして、ToDoを管理するためのモデルを作成する。

テーブル定義

ひとまずは必要最低限のものに絞ってリストアップする。

  • ToDo情報
    • ID
    • ToDo内容
    • 登録日
    • 更新日

上の内容をコードにするとこんな感じになる。
必要な import は物を適宜追加する。

class Task(Base):
    __tablename__ = 'tasks'
    id = Column(Integer, primary_key=True)
    summary = Column(Text)
    created_at = Column(DateTime, default=datetime.datetime.now())
    updated_at = Column()

DB初期化用のファイル script/initializedb.py には先ほど削除した MyModel が残っているため該当部分を削除する。
また、初期値として登録するものはないためその部分も削除する。

from ..models import (
    DBSession,
    MyModel,  <- 削除する
    Base,
    )

def main(argv=sys.argv):
    (省略)
    with transaction.manager:
        model = MyModel(name='one', value=1)  <- 削除する
        DBSession.add(model)                  <- 削除する
        pass                                  <- 追加する

データベースのマイグレーション

alembicのインストール

Djangoとは異なり、マイグレーションをするに辺りそれ用のモジュールをインストールする必要があるらしい。
マイグレーション用モジュールとして alembic をインストールする。

(pyramid_python)> pip install alembic

インストール後の pip list は以下のようになる。
特にバージョン番号を指定していないから、インストールする度にバージョン番号が変わる。

(pyramid_python)> pip list
alembic (0.8.2)
chameleon (2.22)
mako (1.0.1)
markupsafe (0.23)
PasteDeploy (1.5.2)
pip (7.1.2)
pygments (2.0.2)
pyramid (1.5.7)
pyramid-chameleon (0.3)
pyramid-debugtoolbar (2.4)
pyramid-mako (1.0.2)
pyramid-tm (0.12)
python-editor (0.4)
repoze.lru (0.6)
setuptools (12.0.5)
sqlalchemy (1.0.8)
ToDoManager (0.0, e:\developments\pycharmprojects\todomanager\todomanager)
transaction (1.4.4)
translationstring (1.3)
venusian (1.0)
waitress (0.8.9)
WebOb (1.4.1)
zope.deprecation (4.1.2)
zope.interface (4.1.2)
zope.sqlalchemy (0.7.6)

alembic を使うために次のコマンドで初期化する。

(pyramid_python)> alembic init alembic

こんな感じのログが出力されて必要なファイルが生成される。

Creating directory E:\Developments\PycharmProjects\ToDoManager\ToDoManager\alembic ... done
Creating directory E:\Developments\PycharmProjects\ToDoManager\ToDoManager\alembic\versions ... done
Generating E:\Developments\PycharmProjects\ToDoManager\ToDoManager\alembic.ini ... done
Generating E:\Developments\PycharmProjects\ToDoManager\ToDoManager\alembic\env.py ... done
Generating E:\Developments\PycharmProjects\ToDoManager\ToDoManager\alembic\README ... done
Generating E:\Developments\PycharmProjects\ToDoManager\ToDoManager\alembic\script.py.mako ... done
Please edit configuration/connection/logging settings in 'E:\\Developments\\PycharmProjects\\ToDoManager\\ToDoManager\\alembic.ini' before proceeding.

alembicの設定

生成された alembic.inisqlalchemy.url を変更する。
今はSQLiteを使用しているので以下のように書き換える。

sqlalchemy.url = driver://user:pass@localhost/dbname
↓
sqlalchemy.url = sqlite:///%(here)s/ToDoManager.sqlite

サーバを起動させるために作成したテーブルなどを一度削除する。
SQLiteなので今回は手っ取り早く ToDoManager.sqlite ファイルを削除する。

alembic/env.py#add your model's MetaData object here とコメントが書かれている辺りに次のコードを追記する。

from todomanager.models import Base
target_metadata = Base.metadata

マイグレーションファイルの生成

テーブルの状態と models.py の差分で自動的にマイグレーションファイルを生成するモードがあるのでそれを利用する。

(pyramid_python)> alembic revision --autogenerate -m "Create Task model"

こんな感じのログが出力されて、マイグレーションに必要なファイルが生成される。

INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.autogenerate.compare] Detected added table 'tasks'
Generating E:\Developments\PycharmProjects\ToDoManager\ToDoManager\alembic\versions\809bd8fbc9_create_task_model.py ... done

生成されたマイグレーションファイルファイルはこんな感じになる。
リビジョン番号は、マイグレーションファイルを識別するためのコードのため、ファイルを生成する度に異なる。

# revision identifiers, used by Alembic.
revision = '809bd8fbc9'
down_revision = None
branch_labels = None
depends_on = None

from alembic import op
import sqlalchemy as sa


def upgrade():
    ### commands auto generated by Alembic - please adjust! ###
    op.create_table('tasks',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('summary', sa.Text(), nullable=True),
    sa.Column('created_at', sa.DateTime(), nullable=True),
    sa.Column('updated_at', sa.DateTime(), nullable=True),
    sa.PrimaryKeyConstraint('id')
    )
    ### end Alembic commands ###


def downgrade():
    ### commands auto generated by Alembic - please adjust! ###
    op.drop_table('tasks')
    ### end Alembic commands ###

ドキュメントを見ると、マイグレーションファイルの自動生成する際に、変更を検知できる項目とできない項目があるらしい。

変更を検知できるもの

  • テーブルの追加と削除
  • カラムの追加と削除
  • カラムのnullステータス
  • インデックスやユニーク制約などの基本的な変更
  • 外部参照キーの基本的な変更

変更を検知できないもの

  • テーブル名の変更
  • カラム名の変更
  • 無名のインデックスなど

詳細はここ Auto Generating Migrations で確認できる。

マイグレーションの実行

生成されたマイグレーションファイルを使用してデータベースのマイグレーションをする。

  • 状態を確認する

    alembic current コマンドを入力して状態を確認する。

      (pyramid_python)> alembic current
      INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
      INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
    
  • マイグレーションを実行する

    alembic upgrade header コマンドでマイグレーションを実行する。

      (pyramid_python)> alembic upgrade head
      INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
      INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
      INFO  [alembic.runtime.migration] Running upgrade  -> 809bd8fbc9, Create Task model
    

    upgrade には、 リビジョン番号head が指定できる。 それ外にも +N 表記でも可能らしい。

  • マイグレーションの実行を取り消す

    alembic downgrade -1 コマンドでマイグレーションを取り消せる。

      (pyramid_python)> alembic downgrade -1
      INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
      INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
      INFO  [alembic.runtime.migration] Running downgrade 809bd8fbc9 -> , Create Task model
    

    downgrade には、 リビジョン番号-N が指定できる。

  • マイグレーションの履歴を確認する

    alembic history コマンドでマイグレーションの履歴を確認できる。

      (pyramid_python)> alembic history
      <base> -> 809bd8fbc9 (head), Create Task model
    

(追記)
上記の変更を反映したコードをコミット。

github.com

view.py について変更し忘れていたため、修正したコミット。

github.com

PyramidでToDo管理サービスを作る 【プロジェクト作成】 (リトライ編)

前回の記事で作成したプロジェクトだと、データベースが設定されていないものだったので再度プロジェクトを作成する。

neoinal.hatenablog.com

内容としては、「プロジェクトの作成からサーバの起動」からとなる。

プロジェクトの作成からサーバの起動

  1. scaffoldを使ってプロジェクトを作成

     (pyramid_python)> pcreate -s alchemy ToDoManager
    

    実行するといろんなファイルが作成される。ディレクトリ構成としてはこんな感じ。
    前回のディレクトリ構成と比較すると、 scripts ディレクトリや models.py などが増えている。

     E:.
     │  .gitignore
     │  CHANGES.txt
     │  development.ini
     │  LICENSE
     │  MANIFEST.in
     │  production.ini
     │  README.md
     │  README.txt
     │  setup.py
     │
     └─todomanager
         │  models.py
         │  tests.py
         │  views.py
         │  __init__.py
         │
         ├─scripts
         │  │  initializedb.py
         │  │  __init__.py
         │  │
         │  └─__pycache__
         ├─static
         │      pyramid-16x16.png
         │      pyramid.png
         │      theme.css
         │      theme.min.css
         │
         ├─templates
         │      mytemplate.pt
         │
         └─__pycache__
    
  2. setup.py の修正

    前回の失敗を繰り返さないために setup.py を修正する。

     with open(os.path.join(here, 'README.txt')) as f:
                                          ↓
     with open(os.path.join(here, 'README.md'), encoding='utf-8') as f:
    
  3. 作成したプロジェクトを実行

    必要なモジュールをインストールする。

     (pyramid_python)> python setup.py develop
    

    起動させるために次のコマンドを入力する。

     (pyramid_python)> pserve development.ini
    

    だがしかし、以下のエラーが出力される。
    どうやらデータベースの初期化が済んでないとのこと。

    Pyramid is having a problem using your SQL database. The problem might be caused by one of the following things:

    1. You may need to run the "initialize_ToDoManager_db" script to initialize your database tables. Check your virtual environment's "bin" directory for this script and try to run it.

    2. Your database server may not be running. Check that the database server referred to by the "sqlalchemy.url" setting in your "development.ini" file is running.

    After you fix the problem, please restart the Pyramid application to try it again.

    コマンドを叩いてデータベースを初期化する。
    デフォルトの設定のままなので、SQLiteが使用される。

     (pyramid_python)> initialize_ToDoManager_db development.ini
    

    このままだと、一緒に .sqlite ファイルもコミットする可能性があるので .gitignore に追加する。

     # Database
     *.sqlite
    

    気を取り直して再度起動する。

     (pyramid_python)> pserve development.ini
    

    以下のログが出力されて起動する。

     Starting server in PID 4192.
     serving on http://0.0.0.0:6543
    

    ブラウザで「http://localhost:6543」にアクセスすると前回と同じ画面が表示される。

リポジトリの方は、消さずに不要なファイルを消して上書きしておこう。

PyramidでToDo管理サービスを作る 【プロジェクト作成】

実行環境

GitHubにプロジェクトを作る

右上にある「+」マークからリポジトリを作る。 プロジェクト名は読んで字の如く「ToDoManager」とでもしておこう。 説明は省略して練習も兼ねてるのでライセンスは取り敢えず「MIT License」にでもしておくかな。

出来上がったリポジトリgithub.com

作ったリポジトリをクローンする

GitHub for Windowsを使ってリポジトリを適当な場所にクローンする。

プロジェクトの作成からサーバの起動

  1. scaffoldを使ってプロジェクトを作成

     (pyramid_python)> pcreate -s starter ToDoManager
    

    ココらへんは他のウェブフレームワークと大差ない感じ。
    実行するといろんなファイルが作成される。ディレクトリ構成としてはこんな感じ。

     E:.
     │  .gitignore
     │  CHANGES.txt
     │  development.ini
     │  LICENSE
     │  MANIFEST.in
     │  production.ini
     │  README.md
     │  README.txt
     │  setup.py
     │
     └─todomanager
         │  tests.py
         │  views.py
         │  __init__.py
         │
         ├─static
         │      pyramid-16x16.png
         │      pyramid.png
         │      theme.css
         │      theme.min.css
         │
         ├─templates
         │      mytemplate.pt
         │
         └─__pycache__
    
  2. GitHubにプッシュ

    GitHubから一度クローンしたのもあって、READMEファイルがダブってるためscaffoldで生成されたREADME.txtの方を削除する。 この状態のプロジェクトを一度コミットする。コミット先はひとまずmasterブランチ。
    そしてGitHubにプッシュする。

  3. 作成したプロジェクトを実行

    実行するためには、作成したプロジェクトを仮想環境上にインストールする必要があると。
    以下のコマンドを入力してセットアップする。

     (pyramid_python)> python setup.py develop
    

    うぐぅ……README.txtを削除したことによりエラーが発生。
    setup.pyの該当部分を修正する。

     with open(os.path.join(here, 'README.txt')) as f:
                                          ↓
     with open(os.path.join(here, 'README.md'), encoding='utf-8') as f:
    

    ファイルの拡張子を変更して、明示的に文字コードを指定。
    修正したファイルを再度GitHubにプッシュする。
    気を取り直して再度セットアップコマンドを実行すると問題なく完了。

    起動するには以下のコマンドを入力する。

     (pyramid_python)> pserve development.ini
    

    実行すると以下の様なログが出力されて起動する。

     Starting server in PID 7772.
     serving on http://0.0.0.0:6543
    

    ブラウザで「http://localhost:6543」にアクセスするとこんな感じの画面が表示される。

f:id:neoinal:20150806233253p:plain

今日はここまで。 あんまり進まないな……。

PyramidでToDo管理サービスを作る 【環境構築】

事の発端

2015年内にやりたいこと一覧の中で「何かしらのWebサービスを作る」というのがあったものの、なかなか手を付けずに8月を迎えてしまった。
挙げたからには達成させたいので「ToDo管理サービスを作成する」と明言することでひとまずの退路を断っておこうと思う。
手探り状態でやるので結構時間が掛かりそうな予感……

Pyramidとは

Pythonで書かれたウェブフレームワークのこと。
サイト:Pylons Project : Pyramid : About

ちなみにPyramid以外にも、Djangoとかがある。
元々はDjangoをいじっていたのだけれども、なんとなくPyramidにしてみた。

実行環境

環境を整える

  1. Pythonをインストール

    Pyramidは、1.3a1以降であればPythonの2でも3でも動作する。
    後でvirtualenvだったりvenvで仮想環境を構築するので、適当なバージョンをインストールする。
    取り敢えずPython 3.4.3をインストールした。
    インストール手順については、特に難しいことはないので省略。
    基本的には「Next」連打で問題無い筈。環境パスに設定するなら途中でその項目を有効にする必要がある。

  2. Pythonの仮想環境を構築

    もし仮想環境を使用しないのであれば、このステップをスキップして3番を実行すればいいです。
    ただPyramidのチュートリアル曰く、仮想環境でやることを推奨してるみたい。
    仮にいらなくなったのなら仮想環境の方を削除すれば良いわけだしね。

    • virtualenvを使う

        python -m virtualenv pyramid_python
      
    • venvを使う

        python -m venv pyramid_python
      
  3. Pyramidのインストール

    Pyramidをインストールする。
    仮想環境を構築したのなら、以下のコマンドを入力して環境パス等を設定する。

     ./pyramid_python/Scripts/activate.bat
    
    • easy_installを使う

        easy_install "pyramid==1.5.7"
      
    • pipを使う

        pip install "pyramid==1.5.7"
      

取り敢えず今回はここまで。

次は、GitHubリポジトリ作ってまっさらなプロジェクトをコミットするところまでかな?

Rust言語にさわってみる その2

前回は、Rust言語の公式ページにあったHello Worldプログラムを実行した。 neoinal.hatenablog.com

今回は、Hello Worldプログラムで使われた内容をRust言語のHello Worldページを参考にして理解してみる。

ちなみにHello Worldプログラムで使ったコードは以下のものになります。

fn main() {
    println!("Hello, world!");
}

関数の書き方

関数は、fn method で始まり {} で囲まれたブロックを用意することで定義できる。 こんな感じ。

fn method() {

}

この定義だと、引数と戻り値が無い method関数 が定義されると。

CやJavaと同様に、method名が main となっているものは特別な関数となり、 プログラムを実行した際に呼び出される関数となる。

fn main() {

}

関数に引数を渡した場合や戻り値を返す場合は、どう書くのだろうか?
読んだ限り、引数は 関数定義の () の中に記述すればいいらしい。
でも具体的な書き方までは書いて無いし、戻り値についても記述が無い…
それはおいおい見ていこう。一先ずは、Hello Worldプログラムの理解が先だ。

処理の記述について

定義した関数の {} 内に処理を記述する。
インデントはタブではなくスペースで調整するらしい。
1つの処理が終わったら行末にセミコロン( ; )を書く必要がある。
ここら辺はC言語に似ている感じかな。

マクロの呼び出し

Hello Worldプログラムでは、 main 関数の中に println!("Hello, world!"); という記述がある。
この println!() はRustで定義されているマクロを呼び出す書き方になる。
関数として呼び出す場合は、 println() のように ! がなくなる。
ただこのマクロ、C言語のマクロとは違う模様。

なんか色々細かい部分をすっ飛ばした気がするけど、ここら辺が分かってればとりあえず大丈夫かな?
ここ間違ってるとかがあれば是非指摘してください。
英語苦手で翻訳機に突っ込んだ結果とコードで理解しようとしているので…

Rust言語にさわってみる

Rust言語とは

Mozillaによって開発されているプログラム言語で、以下の特徴があるらしい。

  • 実行速度が早い
  • セグメンテーション違反を防ぐ
  • スレッドセーフ

ちなみに2015年5月に1.0.0が出て6月に1.1.0が出た模様。

インストール

取り敢えず、公式ページにいってインストールしてみる。

トップページにある、Installボタンからインストーラをダウンロードする。
使ってるPCのOSがWindows 8.1の64bitだったので、64bit版がダウンロードされる。
後は、インストーラにしたがってインストールする。

Hello World

一発目のプロジェクトは、お決まりの「Hello World」。

  • 適当なディレクトリを作ってhelloworld.hsファイルを置く。
  • コードを書く
fn main() {
    println!("Hello World!");
}
rustc helloworld.hs
  • helloworld.exeが出来上がるので実行する
E:\Developments\RustProjects\HelloWorld>helloworld.exe
Hello World!

ひとまず公式サイトのドキュメントからソースコードを持ってきたので、何がどうなっているのかそこから見る必要がありそう。
次はRustでFizzBuzzでも作りながらいろいろ調べてみようかな。