Почему синтаксис Scala для кортежей настолько необычен?
в математике и информатике Кортеж-это упорядоченный список элементов. В теории множеств (упорядоченный) N-Кортеж - это последовательность (или упорядоченный список) из n элементов, где n-положительное целое число.
Так, например, в Python 2-й элемент кортежа будет осуществляться через t[1].
в Scala, доступ возможен только через странные имена t._2.
Итак, вопрос в том, почему я не могу получить доступ к данным в кортежах как Последовательность или список, если это по определению? Есть какая-то идея или просто еще не досмотрели?
7 ответов:
Scala знает arity кортежей и, таким образом, может предоставить аксессоры, такие как
_1,_2и т. д., и создать ошибку времени компиляции, если вы выберете_3на пару, например. Более того, тип этих полей-это именно то, что тип используется в качестве параметра дляTuple(например,_3наTuple3[Int, Double, Float]вернет aFloat).если вы хотите получить доступ к N-му элементу, вы можете написать
tuple.productElement(n), но возвращаемый тип может быть толькоAny, так что вы теряете тип информация.
Я считаю, что следующий отрывок из "программирование в Scala: всестороннее Пошаговое Руководство" (Мартин Одерский, Лекс Спун и Билл Веннерс) непосредственно затрагивает оба ваших вопроса:
доступ к элементам кортежа!--7-->
Вы можете быть удивлены, почему вы не могу получить доступ к элементам кортежа, как элементы списка, например, с "pair (0)". Причина что метод apply списка всегда возвращает один и тот же тип, но каждый элемент кортежа может быть другого типа: _1 может иметь один результат типа, _2 другой, и так далее. Вместо этого эти _n числа основаны на одном на основе нуля, потому что начиная с 1-это традиция, установленная другими языки со статически типизированными кортежами, такие как Haskell и ML.
кортежи Scala получают очень мало предпочтений в отношении синтаксиса языка, кроме выражений
'(' a1, ..., an ')'обрабатывается компилятором как псевдоним скала.Tuplen (a1, ..., Ан) при создании экземпляра класса. В противном случае кортежи ведут себя как любые другие объекты Scala, фактически они записываются в Scala как case классы, которые варьируются от Tuple2 до Tuple22. Tuple2 и Tuple3 также известны под псевдонимами Pair и Triple соответственно:val a = Pair (1,"two") // same as Tuple2 (1,"two") or (1,"two") val b = Triple (1,"two",3.0) // same as Tuple3 (1,"two",3.0) or (1,"two",3.0)
одна большая разница между
List,Seqили любая коллекция и Кортеж - это то, что в кортеже каждый элемент имеет свой собственный тип, где в списке все элементы имеют один и тот же тип.и как следствие, в Scala вы найдете такие классы, как
Tuple2[T1, T2]илиTuple3[T1, T2, T3], Так что для каждого элемента у вас также есть параметр типа. Коллекции принимают только 1 параметр типа:List[T]. Синтаксис как("Test", 123, new Date)- это просто синтаксический сахар дляTuple3[String, Int, Date]. И_1,_2и т. д. это просто поля на кортеже, что вернуть соответствующий элемент.
вы можете легко достичь этого с бесформенные:
import shapeless.syntax.std.tuple._ val t = ("a", 2, true, 0.0) val s = t(0) // String at compile time val i = t(1) // Int at compile time // etcмногие методы, доступные для стандартной коллекции, также доступны для кортежей таким образом (
head,tail,init,last,++и:::для конкатенации,+:и:+для добавления элементов,take,drop,reverse,zip,unzip,length,toList,toArray,to[Collection], ...)
при обычном доступе к индексу можно использовать любое выражение, и потребуется некоторое серьезное усилие, чтобы проверить в compiletime, если результат выражения индекса гарантированно будет в диапазоне. Сделайте его атрибутом и ошибкой времени компиляции для
(1, 2)._3образом "бесплатно". Такие вещи, как разрешение только целочисленных констант внутри доступа к элементам на кортежах, были бы очень особым случаем (уродливым и ненужным, некоторые сказали бы смешным), и снова некоторые работы по реализации в компилятор.Python, например, может уйти с этим, потому что он не будет (не мог) проверять (в compiletime, то есть), если индекс все равно находится в диапазоне.
Я думаю, что это для проверки типа. Как delnan говорит, Если у вас есть кортеж
tиндексe(произвольное выражение),t(e)не даст компилятору никакой информации о том, к какому элементу осуществляется доступ (или даже если это допустимый элемент для кортежа такого размера). При доступе к элементам по имени Поля (_2является допустимым идентификатором, это не специальный синтаксис), компилятор знает, к какому полю вы обращаетесь и какой тип он имеет. Такие языки, как Python, на самом деле не имеют типов, так что это им не нужно.
помимо уже упомянутых преимуществ Жан-Филипп Пелле эта нотация также очень распространена в математике (см. http://en.wikipedia.org/wiki/Tuple). многие преподаватели добавляют индексы к переменным кортежа, если они хотят ссылаться на элементы кортежа. И общая (латексная) нотация для записи "с индексом n" (имея в виду n-й элемент кортежа) составляет
_n. Так что я нахожу это на самом деле очень интуитивным.