usingについて。


はいはーい。またまた書きます。

usingについて

昨日のLambdaでも出てきましたが、Haxeにはusingというものがありまして、一言で言えばクラスや特定の型にメソッドを追加し拡張する機能があります。
僕はこれでよく言語間の違いを分けたりしています。

僕は実は、なにげに凄くね?とおもったりしています。特にモナドを実現するために便利な機能でもあると思っています。

usingのキホン

たとえばー、 こんな感じのクラスがあって~,

Foo
class Foo{
    public static function hoge(a, b, c, d){
           // 実装なのれす!!!
    }
}

このusing Foo;するとhogeメソッドをこんな感じにつかえます!!!

Sample.hx
using Foo;
class Sample{
    public static function hoge(a, b, c, d){
          ///  usingをつかわないでかくと
             Foo.hoge(a,b,c,d);
         ///  usingを使ってかくと!
             a.hoge(b,c,d);
    }
}

ぶっちゃけこれだけ!!!!

ちょっと解説

どーしてhogeが呼び出せるの????

Haxeでusingをつかうと、そのクラスのpublic static メソッド第一引数とマッチする型であれば、その型のメソッドとして呼びだせる、というわけです。

実例!!!

そうですねー、たとえばInt型を拡張してみましょう。

  • 3の倍数であればFizz
  • 5の倍数であればBuzz
  • 15の倍数であればFizzBuzz
  • それ以外は、その数値

を返すメソッドをInt型に追加しましょう。

返す値の型を作る

さてさて、Haxeは一つの関数は同じ型を返さなければなりません。このままでは、Intとfizzbuzzの文字列で型が違います。なので、今回はfizzbuzz型を作ります。全部文字列にしても良いのですが、Haxeらしく書くならenumで書くとHaxeらしいです。

FizzBuzz.hx
enum FizzBuzz{
    Fizz;
    Buzz;
    FizzBuzz;
    Number(i:Int);
}

あ、そうそう、Haxeのenumについてもまた別の記事にでも詳しく書いてみたいと思います。

public staticだらけのクラスを作る

つぎに、数値を引数に与えたら、FizzBuzz型に変換してかえすpublic staticメソッドをFizzBuzzConverterクラスにつくります。

FizzBuzzConverter.hx
class FizzBuzzConverter{
    public static function toFizzBuzz(i : Int) {
        return  if( i % 15 == 0 ){
            FizzBuzz;
        }else if( i % 3 == 0 ){
            Fizz;
        }else if( i % 5 == 0){
            Buzz;
        }else{
            Number(i);
        }
    }
}

とりあえずusingなしで使ってみる。

Sample.hx
class Sample{
    public static function main(){
        trace(ToFizzBuzz.fizzbuzz(6));
        trace(ToFizzBuzz.fizzbuzz(10));
        trace(ToFizzBuzz.fizzbuzz(30)); 
        trace(ToFizzBuzz.fizzbuzz(7));
    }
}

とりあえず出力

Sample.hx:3: Fizz
Sample.hx:4: Buzz
Sample.hx:5: FizzBuzz
Sample.hx:6: Number(7)

良いですね。

usingで書いてみる

Sample.hx
using FizzBuzzConverter;
class Sample{
    public static function main(){
        trace(6.toFizzBuzz());
        trace(10.toFizzBuzz());
        trace(30.toFizzBuzz()); 
        trace(7.toFizzBuzz());
    }
}

良い感じですねー。

もっと詳しく詳細解説ぅ!!!!

呼び出されるメソッドの優先順位

たとえば、usingで拡張されたメソッドと元々のクラスのメソッドが競合したとき、また、複数のusingが競合したときどうなるか?しらべてみた。

結論から言えば

  • 元々のクラスにメソッドがあった、場合、そのクラスのメソッドが呼びだされる。
  • 最後にusingされたクラスのメソッドが呼びだされる。

となりました。まぁ妥当でしょう。

元々のクラスにメソッドがあった場合

たとえばusingのために以下のクラスがあったとしましょう。

Foo.hx
class Foo{
    public static function copy(a){
        return ["foo"];
    }
}

さて、Arrayにはcopyメソッドがあります。ので、Fooをusingしても、Foo.copyメソッドは呼び出されません。

Sample.hx
using Foo;
using Foo;

class Sample{
    public static function main(){
        trace(Foo.copy([1,2,3])); // => ["foo"]
        trace([1,2,3].copy()); // => [1,2,3]
    }
}

using同士で競合している場合

以下のFooとBarクラスがあったとします。

Foo.hx
class Foo{
    public static function copy(a){
        return ["foo"];
    }
}
Bar.hx
class Bar{
    public static function copy(a){
        return ["bar"];
    }
}

これを、このように呼びだします。

Sample.hx
using Foo;
using Bar;

class Sample{
    public static function main(){
        trace(1.copy()); //=> [“bar"]
    }
}

このように、Barのメソッドが優先されます。

以上です。

次は僕じゃないれすよー!!!
6日目は@hatchineeさんですよろしくおねがいします。