空のリストの等価性はどのように機能しますか?

== 演算子は本当にListを内容で比較しますか?特に空のリストに関しては?

以下の比較は予想通りに機能します。

List("A", "B", "C") == "ABC".split("").toList//true
List() == List()//true
List.empty[String] == List.empty[String]//true

しかし、異なる型の空リスト比較は混乱を招く結果になります。

List.empty[String] == List.empty[Int]//true: on different types?

編集:最初の質問で、私はAndreyによって明らかにされている誤解を招くようなテストケースを作りました。ありがとう。ここに再現

val emptyStrSplit = "".split("").toList//List("") and not List() as displayed in Console
List.empty[String] == emptyStrSplit//false: b/c List() != List("")
2
ru de
こんにちは、 "" .split( "")。toList の出力 List()に困惑し、サイズの確認に失敗しました、ありがとうだから問題はかなりばかげている。唯一興味深い部分は、異なるタイプの2つの空のリスト List.empty [T1] == List.empty [T2] をチェックする方法になりました。それに応じて質問を編集します
追加された 著者 Polymerase,
toString はぎこちなくあいまいです - List( "")の空の文字列は印刷出力には表示されないため、 List()のようになります。 。
追加された 著者 user2357112,
"" .split( "")。toListList()ではありません。これは List( "")です。 "" .split( "")が空であるという誤った仮定を取り除いた後でも、質問はまだ重要な何かを尋ねますか?
追加された 著者 Andrey Tyukin,

4 答え

  • List.empty[String] is the singleton object Nil, which extends List[Nothing] (covariantly, subtype of List[String]).
  • List.empty[Int] is the singleton object Nil, which extends List[Nothing] (covariantly, subtype of List[Int]).
  • Every singleton object is equal to itself.
  • Therefore, Nil == Nil gives true.

したがって、基本的には、 List [String] 型と List [Int] 型の両方のオブジェクトである Nil が1つあります。それはあなたがサブタイプを持っているならあなたが得るものです。ここに奇妙なことや矛盾することは何もない。

型が同じであることを確認したい場合は、 A =:= B 型の暗黙的証拠をデフォルト値 null と共に使用できます。次に、 null 以外の証拠がコンパイラによって提供されているかどうかを確認します。

def eqSameType[A, B](a: A, b: B)(implicit ev: A =:= B = null) = 
  if (ev == null) false else a == b

例:

scala> eqSameType(List.empty[Int], List.empty[String])
res4: Boolean = false
5
追加された
ああ今、私はその理由がわかります。説明をありがとう。それでもビジネスロジックレベルです。カスタマイズされたコンパレータを使用しても、 List.empty [String] == List.empty [Int]false を返すことが望ましいです。以下の完全な答えを見てください
追加された 著者 Polymerase,
さらに良くなりました! Brianのテストケースにも合格します。 A =:= B = null という構文は何ですか。さらなる文書を読みたいのですが。
追加された 著者 Polymerase,
@ポリメラーゼいいえ、必ずしも「望ましい」とは限りません。 xy が異なるタイプの場合、 x == y がまったくタイプチェックされないのであれば、より望ましいと考える人もいます。マルチバーサル平等
追加された 著者 Andrey Tyukin,
回避策を適用して@Polyraseを更新しました。
追加された 著者 Andrey Tyukin,
@Polymerrase =:= はバイナリの中置型コンストラクタです( =:= [= A、B] の場合はsugar)、 = null はデフォルトです。タイプ A =:= B の引数 ev の値。私は =:= のことを「一般化型制約」と呼んでいます。
追加された 著者 Andrey Tyukin,

タイプ消去の問題や「実際には同じオブジェクト」の問題を無視しても、 Seqequals に関するドキュメントには次のように記載されています。

defは等しい(that:Any):Boolean

     

任意のシーケンスに対するequalsメソッド。

     

戻り値:このシーケンスと同じ順序で同じ要素を持つシーケンスである場合はtrue、それ以外の場合はfalse。

これはすべての空のシーケンスを等しくします。それらは同じ順序で同じ要素を持ちます、すなわちnoneです。空の List は、空の VectorQueueStream などと同じです。

また、タイプセーフな同等性を提供するライブラリに興味があるかもしれません。 ScalacticScalaz など

4
追加された

List.empty [T] (または List [T]())が List の新しいインスタンスを返した場合でも、Andreyの回答に追加します。それでも、型消去のために、さまざまな型の空のリストが等しいことを期待する必要があります。たとえば、 ListBuffer では、 empty メソッドは毎回新しい ListBuffer を返します。

import scala.collection.mutable.ListBuffer
ListBuffer.empty[Int] == ListBuffer.empty[String]

2つのリストのコンパイル時の型が異なる場合を検出する方法が必要な場合は、 TypeTags

import scala.reflect.runtime.universe.{ TypeTag, typeTag }

def equalAndSameType[A: TypeTag, B: TypeTag](as: Seq[A], bs: Seq[B]) =
  typeTag[A] == typeTag[B] && as == bs

equalAndSameType(List.empty[Int], List.empty[String])//returns false

ただし、これがいつ役に立つのかはわかりません。

1
追加された
おお、かっこいい、数秒以内に同じアイディアを思いついたようだ。ところで、 TypeTagClassTag の使い方について詳しく教えてください。
追加された 著者 Polymerase,
素晴らしい、洞察力をありがとう。
追加された 著者 Polymerase,
@Polyraseドキュメントへのリンクを参照してください。タイプタグには総称に関するより多くの情報があるので、クラスタッグベースの解決策はより深くネストされた総称では失敗します。 equalAndSameType(List.empty [List [文字列]]、List.empty [List [Int]])を考えます。それは実際にはあなたの答えが失敗するという稀なケースです。
追加された 著者 Brian McCutchon,

編集: ClassTag を使ったこの実装は十分ではありません。 TypeTag を使ったBrianの答えはもっと良いです。

Andreyの答えはScalaの観点からは完全に理にかなっていますが。 List.empty [String] == List.empty [Int] をtrueではなくfalseにするとビジネス的に意味があると思います。以下は、以下をサポートするためにコンテキストバインドを使用したカスタムコンパレータです。それが最もエレガントな方法かどうかわからない。

import scala.reflect.{ClassTag, classTag}

def customCompareLists[T1: ClassTag, T2: ClassTag](l1: List[T1], l2: List[T2]): Boolean = {
  classTag[T1] == classTag[T2] && l1 == l2
}

customCompareLists(List(), List())//true
customCompareLists(List.empty[Double], List.empty[Double])//true
customCompareLists(List.empty[String], List.empty[Int])//false
customCompareLists(List(1,2), List("A"))//false
customCompareLists(List(1,2), List(1,2))//true

// FAILED on this case
customCompareLists(List.empty[List[String]], List.empty[List[Int]])//true: INCORRECT
0
追加された
私は「ビジネス上の意味がよりよくなる」ことがあなたのユースケースに依存すると思う。
追加された 著者 Brian McCutchon,