Erlangでの強制型キャスト

Erlangでの強制型キャスト



アーランは多くの点でユニークな言語です。 私は最近それを研究し始めました、そして、私はプログラミングで10年以上の経験を持っていますが、さまざまな点でその柔軟性と便利さで私を驚かせ続けています。

しかし、Erlangでは利用できない大きな「BUT」が1つあります。これは自動キャストです。 最近のほとんどのプログラミング言語で暗黙的な型変換によって破損した人物として、ソースデータの種類を考えないようにするモジュールをスケッチしました。

私自身のErlangベースのCMSを作成する過程で、私は常にそれを使用し、他のErlangプログラマーに推奨しています。



どこで、どこで?



タイプ変換の問題は、ソースタイプの定義と必要なものへの変換という2つの部分で構成されています。 Erlangには両方の手順用の組み込みツールがありますが、残念ながら頻繁に使用するには便利ではありません。



型定義



ソースデータのタイプを確認するために、erlangモジュールの関数セットがあります。 それらはすべてis_プレフィックスで始まります。 これらの関数の良い点は、ガードとして使用できることです。 初心者の場合:ガードは、機能を開始する前のアーランの組み込みデータチェックです。

正面攻​​撃として、直接変換に同様の方法を使用できます。



to_list(Item) when is_atom(Item)-> ...;

to_list(Item) when is_binary(Item)-> ...;

...








型キャスト



ほとんどの型は、同じモジュールの組み込み関数を使用して簡単に他の型に変換できます。 問題はないと思われるので、タイプを比較し、適切なタイプにします。

しかし、すべての組み込み型を処理するには、少なくとも怠comparisonが許す以上の比較を行う必要があります。

したがって、別の機能を使用して、手順全体をいくつかのステップに分割しました-適用します。

アリティ3のこの関数(アリティはErlang用語、関数に渡されるパラメーターの数)は、モジュール名のアトム、関数名のアトム、データの配列を受け取り、指定された関数の結果を返します。 ドキュメントには、この関数の別のアリティ-2が示されていますが、この場合、モジュール間の競合が発生する可能性があります。



どうした





最初の関数forceは、元のデータ型を定義し、2番目の関数passを呼び出します。 2番目の関数は、元の型と必要な型からの型変換のシステム関数への呼び出しを収集し、削減された値を返します。

途中で、モジュールを使いやすくするために略語が追加されました。



残念ながら、そのような直接的な強制のすべてのタイプが可能であったわけではありません。 したがって、直接キャストが不可能な場合、データは最初にユニバーサル中間型であるリスト型にキャストされ、次に必要な型にキャストされます。



このモジュールの使用は、信じられないほど原始的です:

force:to_list('this_is_a_long_atom')









コードは読みやすく、自己文書化されています。



 % ===================================================================================== % CMSaaS - Content Management System as a Service % % @copyright 2011 CMSaaS dev team % @version 0.1 % All rights reserved. % % CC-Attribution License % % Redistribution and use in source and binary forms, with or without modification, are permitted provided % that the following conditions are met: % % * Redistributions of source code must retain the above copyright notice, this list of conditions and the % following disclaimer. % * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and % the following disclaimer in the documentation and/or other materials provided with the distribution. % * Neither the name of the authors nor the names of its contributors may be used to endorse or promote % products derived from this software without specific prior written permission. % % THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED % WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A % PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR % ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED % TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) % HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING % NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE % POSSIBILITY OF SUCH DAMAGE. % ===================================================================================== -module(force). -export([get_type/1, to_list/1, to_list/2, to_atom/1, to_atom/2, to_binary/1, to_binary/2, to_integer/1, to_integer/2, to_bitstring/1, to_bitstring/2, to_float/1, to_float/2, to_pid/1, to_pid/2, to_tuple/1, to_tuple/2]). force(Item, New_type) -> force(Item, New_type, []) . force(Item, New_type, Options) when is_list(Item)-> pass(Item, 'list', New_type, Options); force(Item, New_type, Options) when is_atom(Item)-> case New_type of 'list' -> pass(Item, 'atom', New_type, Options) ; 'binary' -> New_option=case Options of [] -> [utf8]; X -> X end, pass(Item, 'atom', New_type, New_option) ; _ -> pass(pass(Item, 'atom', 'list', []), 'list', New_type, Options) end ; force(Item, New_type, Options) when is_binary(Item)-> case New_type of 'atom' -> New_option=case Options of [] -> [utf8]; X -> X end, pass(Item, 'binary', New_type, New_option) ; 'list' -> pass(Item, 'binary', New_type, Options) ; _ -> pass(pass(Item, 'binary', 'list', Options), 'list', New_type, []) end ; force(Item, New_type, Options) when is_bitstring(Item)-> case New_type of 'list' -> pass(Item, 'bitstring', New_type, Options) ; _ -> pass(pass(Item, 'bitstring', 'list', []), 'list', New_type, Options) end ; force(Item, New_type, Options) when is_boolean(Item)-> case New_type of 'integer' -> pass(Item, 'boolean', New_type, Options) ; 'float' -> pass(Item, 'boolean', New_type, Options) ; _ -> pass(Item, 'atom', New_type, Options) end ; force(Item, New_type, Options) when is_float(Item)-> case New_type of 'list' -> pass(Item, 'float', New_type, Options) ; _ -> pass(pass(Item, 'float', 'list', []), 'list', New_type, Options) end ; force(Item, New_type, Options) when is_integer(Item)-> case New_type of 'list' -> pass(Item, 'integer', New_type, Options) ; _ -> pass(pass(Item, 'integer', 'list', []), 'list', New_type, []) end ; force(Item, New_type, Options) when is_pid(Item)-> pass(pass(Item, 'pid', 'list', []), 'list', New_type, Options) ; force(Item, New_type, Options) when is_port(Item)-> pass(pass(Item, 'port', 'list', []), 'list', New_type, Options) ; force(Item, New_type, Options) when is_reference(Item)-> pass(pass(Item, 'ref', 'list', []), 'list', New_type, Options) ; force(Item, New_type, Options) when is_tuple(Item)-> pass(pass(Item, 'tuple', 'list', []), 'list', New_type, Options) ; force(_Item, New_type, Options) -> pass(pass(undefined, 'atom', 'list', []), 'list', New_type, Options) . pass(Item, Old_type, New_type, _Options) when Old_type==New_type-> Item; pass(Item, Old_type, New_type, Options) -> apply(erlang, list_to_atom(atom_to_list(Old_type)++"_to_"++atom_to_list(New_type)), lists:merge([Item], Options)) . get_type(Item) when is_list(Item)-> 'list'; get_type(Item) when is_atom(Item)-> 'atom'; get_type(Item) when is_binary(Item)-> 'binary'; get_type(Item) when is_bitstring(Item)-> 'bitstring'; get_type(Item) when is_boolean(Item)-> 'atom'; get_type(Item) when is_float(Item)-> 'float'; get_type(Item) when is_integer(Item)-> 'integer'; get_type(Item) when is_pid(Item)-> 'pid'; get_type(Item) when is_port(Item)-> 'port'; get_type(Item) when is_reference(Item)-> 'ref'; get_type(Item) when is_tuple(Item)-> 'tuple'; get_type(_Item) -> undefined. to_list(Item) when is_list(Item) -> Item; to_list(Item) -> force(Item, 'list'). to_list(Item, _Options) when is_list(Item) -> Item; to_list(Item, Options) -> force(Item, 'list', Options). to_atom(Item) when is_atom(Item) -> Item; to_atom(Item) -> force(Item, 'atom'). to_atom(Item, _Options) when is_atom(Item) -> Item; to_atom(Item, Options) -> force(Item, 'atom', Options). to_binary(Item) when is_binary(Item) -> Item; to_binary(Item) -> force(Item, 'binary'). to_binary(Item, _Options) when is_binary(Item) -> Item; to_binary(Item, Options) -> force(Item, 'binary', Options). to_integer(Item) when is_integer(Item) -> Item; to_integer(Item) -> force(Item, 'integer'). to_integer(Item, _Options) when is_integer(Item) -> Item; to_integer(Item, Options) -> force(Item, 'integer', Options). to_bitstring(Item) when is_bitstring(Item) -> Item; to_bitstring(Item) -> force(Item, 'bitstring'). to_bitstring(Item, _Options) when is_bitstring(Item) -> Item; to_bitstring(Item, Options) -> force(Item, 'bitstring', Options). to_float(Item) when is_float(Item) -> Item; to_float(Item) -> force(Item, 'float'). to_float(Item, _Options) when is_float(Item) -> Item; to_float(Item, Options) -> force(Item, 'float', Options). to_pid(Item) when is_pid(Item) -> Item; to_pid(Item) -> force(Item, 'pid'). to_pid(Item, _Options) when is_pid(Item)-> Item; to_pid(Item, Options) -> force(Item, 'pid', Options). to_tuple(Item) when is_tuple(Item)-> Item; to_tuple(Item) -> force(Item, 'tuple'). to_tuple(Item, _Options) when is_tuple(Item)-> Item; to_tuple(Item, Options) -> force(Item, 'tuple', Options).
      
      






All Articles