2010-12-14 9 views
4

は、審美的な理由のために、私は書くことができるようにしたい、と言う:暗黙の変換を介してのInt上の算術演算子をオーバーライド

3/4 

及び/ INTからの暗黙の変換が存在することクラスのメソッドであるました例えば、:

class Foo(val i: Int) { 
    def /(that: Int) = // something 
} 

implicit def intToFoo(i: Int) = new Foo(i) 

これはすべて可能ですか?つまり、Intの/メソッドを「無効にする」ことは可能ですか?

+1

あなたがこれを行うことができるかどうかを伝えるためのScalaエキスパートは十分ではありませんが、私はあなたにこれをしてはいけないと言います。 「Scala Puzzlers」などを構築しようとしているのでなければ、急激な割引で多くの問題を買っているだけです。 – Malvolio

+0

いくつかの文脈を与えるために、私がしようとしているのはURLパターンを指定するURLマッチャーです。 "foo/bar"/34/"some/thing"。明らかに私はあなたや他の何かができましたが、 "foo/bar" \ 34 \ "some/thing"はちょっと変わっています。 /の使用法は、この文脈のコードの読者にとっては、はっきりしているべきだと思います。 –

+0

コメントの例では、暗黙的な変換はInt –

答えて

7

要約:いいえ、できません。

暗黙の解決は、存在しないメソッドを呼び出そうとした場合にのみ発生します。

より「慣用」ソリューションは、独自の擬似番号のタイプを作成することです、のようなもの:

case class Rational(a: Int, b: Int) { 
    // other methods 
} 

val foo = Rational(3, 4) 

または

case class Path(value: String) { 
    def /(other: String): Path = ... 
} 

val p = Path("3")/"4" 
+0

文字通り3/4を書いてみたいが、/の意味は数値分割ではなく、パス分割を意図している。 (質問のコメントを参照してください) –

+0

次に、3をコンストラクタparamとして新しいクラスを作成し、/ on *を定義します。 –

+0

"3"/"4"とします。もう一度、aesteticsの問題。ポイントはできるだけクリーンなDSLにすることです。最も単純なのは、おそらく、ケースクラスn(i:Int)から一般的なアイテムクラスへの暗黙的な変換を伴う "foo"/n(3)/ n(4)まだ私には醜いです。次に、URLパターンでリテラルintを指定することは、実際には役に立たないかもしれません(つまり "foo/bar/3/4/some/thing"を使用するだけではない理由)。 :) –

2

はその何か

trait PathElement[T] { val value: T } 
case class IntElement(value: Int) extends PathElement[Int] 
case class StringElement(value: String) extends PathElement[String] 

case class Path(parts: Seq[PathElement[_]]) { 
    def /(other: Path): Path = copy(parts = parts ++ other.parts) 
} 
object Path { 
    def apply(part: PathElement[_]): Path = Path(List(part)) 
    implicit def int2path(i: Int): Path = Path(IntElement(i)) 
    implicit def str2path(s: String): Path = Path(StringElement(s)) 
} 
のような理由があります

はお役に立てませんか?これは、文字列は、独自の/メソッドを持っていないので、最初の"foo"が暗黙的にPathに変換されるので、これは、作品

import Path._ 
"foo"/3/4/"bar" 

、たとえば、あなたが書くことができるようになります。 IntPathを開始していた場合は、明示的に変換する必要がありますが、Intを無料で入手できます。

+0

これは、私が実際に考慮しなかった素晴らしい点です。問題は、Intがチェーンの最初のものである場合にのみ発生します。最も実用的な目的で問題を解決します。 :) –

1

あなたが本当に達成したいことだけを推測することはもちろんですが、具体的なURLに一致させるだけでなく、指定された文字列から情報を抽出したいと思っています。例えば。 "/foo/21"が指定されている場合、これは"foo"/21と一致することを知りたいだけでなく、値が21の何かをしたいと思っています。

リフトのURIマッチングプロセスが非常に有用であることがわかりましたあなたのユースケースに合っています。 (私はもちろん、非常に単純化されたバージョンを使用しています)リストを使って少し簡単にマッチングさせることができますが、の代わりに/を使う必要があります。

しかし、それはポイントではありません。私が示したいのはないの利点はの暗黙的な変換の代わりにAsInt抽出器を使用して、暗黙的な変換と抽出要するに

object AsInt { 
def unapply(i: String): Option[Int] = try { 
    Some(i.toInt) 
    } catch { 
    case e: java.lang.NumberFormatException => None 
    } 
} 

def matchUrl(url: String) = { 
    val req:List[String] = url.split('/').toList.drop(1) 
    req match { 
    case "foo" :: "bar" :: Nil => println("bar") 
    case "foo" :: AsInt(i) :: Nil => println("The square is " + i*i) 
    case "foo" :: s :: Nil => println("No int") 
    case _ => println("fail") 
    } 
} 

matchUrl("/foo/21") 
matchUrl("/foo/b") 
matchUrl("/foo/bar") 
matchUrl("/foobar") 

// prints: 
// The square is 441 
// No int 
// bar 
// fail 

の電源を使用していますIntString実際には文字列から整数値を取得することができます。明らかに、ネーミングが気に入らなければ、それをより控えめなものに変更することができますが、実際にURLのマッチングを行う場合は、暗黙的にすべてを変換しないでください。

+0

実際には、私がやろうとしていることではありませんが、可能な限りシンプルな方法でURLパターンを指定するのはScalatraですが、すべてを文字列として指定するのではなく型付きの要素で指定します。さて、これは達成するのは比較的簡単ですが、私はちょうど "/メソッドのInt"の部分に困ってしまった。 –

関連する問題