В чем разница между этими двумя вызовами функции, принимающей набор структурных типов?

Почему вызов fn(Iterator("foo") компилируется, но вызов fn(fooIterator) завершается с ошибкой "несоответствие типов; найдено: Iterator[java.lang.String] required: scala.Iterator[ com.banshee.Qx.HasLength]"

object Qx {
    type HasLength = {def length: Int}
    def fn(xs: Iterator[HasLength]) = 3
    var tn = fn(Iterator("foo"))
    var fooIterator = Iterator("foo")
    var tnFails = fn(fooIterator) //doesn't compile
}

Разве это не одно и то же?


person James Moore    schedule 16.05.2010    source источник
comment
Можете ли вы опубликовать сигнатуры итераторов? Могут ли быть дисперсионные аннотации или имплициты?   -  person Dario    schedule 17.05.2010
comment
Это всего лишь стандартный материал библиотеки, дополнительный код не требуется. scala› Iterator(foo) res0: Iterator[java.lang.String] = непустой итератор   -  person James Moore    schedule 17.05.2010


Ответы (2)


Должно быть, это ошибка в представлении уточнений, потому что обе следующие две формулировки работают.

object Qx1 {
    // give length() parens, even though the Iterator definition doesn't have them
    type HasLength = { def length(): Int }

    def fn(xs: Iterator[HasLength]) = 3
    var tn = fn(Iterator("foo"))
    var fooIterator = Iterator("foo")
    var tnFails = fn(fooIterator) //doesn't compile
}

object Qx2 {
    type HasLength = { def length: Int }

    def fn(xs: Iterator[HasLength]) = 3
    var tn = fn(Iterator("foo"))
    // annotate the type of fooIterator before the type inferencer can mis-infer
    var fooIterator: Iterator[HasLength] = Iterator("foo")
    var tnFails = fn(fooIterator) //doesn't compile
}

Редактировать:

Слишком рано утром. Это String с методом length(), у которого есть скобки, что означает, что это правильно, и вы ошибаетесь, думая, что length и length() — это один и тот же метод. (Это хорошая маленькая ловушка, которую я задокументировал ранее.)

person psp    schedule 17.05.2010
comment
Если это просто длина и длина (), не должен ли его первый пример также потерпеть неудачу? var tn = fn (Итератор (foo)) - person Adam Rabung; 18.05.2010
comment
И почему версия Рэндалла Шульца работает с проекцией вида? Я немного сбит с толку. - person James Moore; 18.05.2010
comment
Это просто длина против длины. fn(Iterator(foo)) работает по той же причине, что и аннотация типа fooIterator: ожидаемый тип выражения влияет на предполагаемый тип. В неудачном примере несовместимый тип выводится в объявлении, а затем вызов выполняется в отдельном операторе. - person psp; 19.05.2010

Эта формулировка работает:

object Qx {
    type HasLength = {def length: Int}
    def fn[HL <% HasLength](xs: Iterator[HL]) = 3
    val tn = fn(Iterator("foo"))
    val fooIterator = Iterator("foo")
    val tnFails = fn(fooIterator)
}
person Randall Schulz    schedule 16.05.2010
comment
Мне бы хотелось получить единое объяснение этого комментария и импровизированного комментария о длине с нулевым аргументом и длине с пустыми скобками. У меня такое чувство, что здесь происходит что-то тонкое, чего я не понимаю. - person James Moore; 18.05.2010