2016-09-09 12 views
6

Kotlinでは、+を関数plus()で、*を関数times()でオーバーライドすることができますが、Setsなどのいくつかの場合、好ましい(集合理論)記号/演算子は存在しません。例えば、交差点の場合はA∩B、ユニオンの場合はA∪Bです。Kotlinでは、既存の演算子をオーバーライドできますが、新しい演算子を作成するのはどうですか?

私は自分の演算子を定義できないようですが、演算子に使用する記号を言うための明確な構文はありません。私はオペレーターとして$$する機能を作りたい場合例:

operator fun String.$$(other: String) = "$this !!whatever!! $other" 
// or even 
operator fun String.whatever(other: String) = "$this !!whatever!! $other" // how do I say this is the $$ symbol?!? 

私は両方のために同じエラーを取得:

Error:(y, x) Kotlin: 'operator' modifier is inapplicable on this function: illegal function name

をオペレーターが作成または上書きすることができます何のためのルールは何ですか?

注:慣用的な答えは、一般的に尋ねすることKotlinのトピックがSOに存在しているように、この質問は、意図的に、作者(Self-Answered Questions)によって書かれ、答えています。

答えて

5

Kotlinはoperators to be overriddenの非常に特定のセットを可能にし、あなた使用可能な演算子のリストを変更することはできません。

元の演算子の精神、または数学記号の他の一般的な使い方を維持しようとする演算子をオーバーライドするときは注意が必要です。しかしいつかは典型的なシンボルは利用できません。連合設定たとえば、概念的に、それは理にかなって、それは内蔵のオペレータSet<T>.plus()すでにKotlinが提供する、またはあなたが創造的な取得し、この場合のためにinfix functionを使用することがあるので、簡単に+として扱うことができます。

// already provided by Kotlin: 
// operator fun <T> Set<T>.plus(elements: Iterable<T>): Set<T> 

// and now add my new one, lower case 'u' is pretty similar to math symbol ∪ 
infix fun <T> Set<T>.u(elements: Set<T>): Set<T> = this.plus(elements) 

// and therefore use any of... 
val union1 = setOf(1,2,5) u setOf(3,6) 
val union2 = setOf(1,2,5) + setOf(3,6) 
val union3 = setOf(1,2,5) plus setOf(3,6) 

それともそれは、より明確である:

infix fun <T> Set<T>.union(elements: Set<T>): Set<T> = this.plus(elements) 

// and therefore 
val union4 = setOf(1,2,5) union setOf(3,6) 

とセット演算子のリストを続ける、交差点ので、すべてのプログラマは文字「N」は012に見えるフォントを持っていると仮定すると、シンボルです我々が離れて得ることができる:

val intersect = setOf(1,3,5) intersect setOf(3,5) 

:あなたはすでに、既存の標準ライブラリ中置機能intersect()を使用することができますが

operator fun <T> Set<T>.times(elements: Set<T>): Set<T> = this.intersect(elements) 

// and therefore... 
val intersect = setOf(1,3,5) * setOf(3,5) 

:として

infix fun <T> Set<T>.n(elements: Set<T>): Set<T> = this.intersect(elements) 

// and therefore... 
val intersect = setOf(1,3,5) n setOf(3,5) 

または*の演算子のオーバーロード経由新しいものを発明している場合は、最も近い演算子または関数名を選択する必要があります。列挙型のセットを否定たとえば、多分-オペレータ(unaryMinus())または!演算子(not())を使用します。演算子のオーバーロードは非常に参考にすることができ、またはそれは混乱と混沌につながることができますので、

enum class Things { 
    ONE, TWO, THREE, FOUR, FIVE 
} 

operator fun Set<Things>.unaryMinus() = Things.values().toSet().minus(this) 
operator fun Set<Things>.not() = Things.values().toSet().minus(this) 

// and therefore use any of... 

val current = setOf(Things.THREE, Things.FIVE) 

println(-current)    // [ONE, TWO, FOUR] 
println(-(-current))   // [THREE, FIVE] 
println(!current)    // [ONE, TWO, FOUR] 
println(!!current)   // [THREE, FIVE] 
println(current.not())  // [ONE, TWO, FOUR] 
println(current.not().not()) // [THREE, FIVE] 

を思慮深いこと。コードの可読性を維持しながら、最良のものを決める必要があります。場合によっては、そのシンボルの標準、または元のシンボルに似た置換えの置換、または混乱の可能性がないように説明的な単語を使用することで、演算子が最適な場合があります。

多くの演算子が既に定義されているか、同等の拡張機能があるので、常にKotlin Stdlib API Referenceをチェックしてください。

もうひとつ...

そして、あなたの$$オペレータについて、技術的にあなたにそれを行うことができます。

infix fun String.`$$`(other: String) = "$this !!whatever!! $other" 

しかし、あなたは関数の名前をエスケープする必要があるため、それは意志

val text = "you should do" `$$` "you want" 

これは本当に演算子のオーバーロードではなく、それが関数であれば動作しますcan me made infix

関連する問題