Почему синтаксис 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
. Так что я нахожу это на самом деле очень интуитивным.