О каких скрытых особенностях Scala должен знать каждый разработчик Scala?
Одна скрытая функция в ответе, пожалуйста.
scala
hidden-features
Krzysiek Goj
источник
источник
Ответы:
Хорошо, я должен был добавить еще один. Каждый
Regex
объект в Scala имеет экстрактор (см. Ответ от oxbox_lakes выше), который дает вам доступ к группам совпадений. Таким образом, вы можете сделать что-то вроде:Вторая строка выглядит сбивающей с толку, если вы не привыкли использовать сопоставление с образцом и экстракторы. Всякий раз, когда вы определяете
val
илиvar
, после ключевого слова появляется не просто идентификатор, а скорее шаблон. Вот почему это работает:Правое выражение создает значение,
Tuple3[Int, Double, String]
которое может соответствовать шаблону(a, b, c)
.Большую часть времени ваши шаблоны используют экстракторы, которые являются членами одноэлементных объектов. Например, если вы напишите шаблон как
тогда вы неявно вызываете экстрактор
Some.unapply
.Но вы также можете использовать экземпляры классов в шаблонах, и это то, что здесь происходит. Val regex является экземпляром
Regex
, и когда вы используете его в шаблоне, вы неявно вызываетеregex.unapplySeq
(unapply
вместо того,unapplySeq
что выходит за рамки этого ответа), который выделяет группы соответствия в aSeq[String]
, элементы которого назначаются для того, чтобы переменные год, месяц и день.источник
Определения структурного типа - то есть тип, описываемый теми методами, которые он поддерживает. Например:
Обратите внимание, что тип параметра
closeable
не определен, кроме как у него естьclose
методисточник
Тип-конструктор Полиморфизм (ака типизированный тип)
Без этой функции вы можете, например, выразить идею отображения функции над списком для возврата другого списка или сопоставления функции через дерево для возврата другого дерева. Но вы не можете выразить эту идею вообще без высших видов.
С более высокими типами вы можете поймать идею любого типа, который параметризован с другим типом. Конструктор типа, который принимает один параметр, называется добрым
(*->*)
. Например,List
. Конструктор типов, который возвращает другой конструктор типов, называется добрым(*->*->*)
. Например,Function1
. Но в Scala у нас выше виды, поэтому у нас могут быть конструкторы типов, параметризованные другими конструкторами типов. Так что они типа((*->*)->*)
.Например:
Теперь, если у вас есть
Functor[List]
, вы можете отобразить списки. Если у вас естьFunctor[Tree]
, вы можете нанести на карту деревья. Но что еще более важно, если у вас естьFunctor[A]
для любого типа А(*->*)
, вы можете отобразить функцию поверхA
.источник
Экстракторы, которые позволяют заменить грязный
if-elseif-else
стиль кода на шаблоны. Я знаю, что они не совсем скрыты, но я использовал Scala в течение нескольких месяцев, не понимая их силу. Для (длинного) примера я могу заменить:С этим, что гораздо понятнее, на мой взгляд
Я должен сделать немного работы в фоновом режиме ...
Но этот труд стоит того, что он разделяет кусок бизнес-логики на разумное место. Я могу реализовать свои
Product.getCode
методы следующим образом ..источник
Манифесты, которые являются своего рода способом получения информации о типе во время выполнения, как если бы Scala имела усовершенствованные типы.
источник
В scala 2.8 вы можете использовать хвостовые рекурсивные методы, используя пакет scala.util.control.TailCalls (фактически это батут).
Пример:
источник
Классы Case автоматически смешивают черту Product, предоставляя нетипизированный, индексированный доступ к полям без какого-либо отражения:
Эта функция также предоставляет упрощенный способ изменить выходные данные
toString
метода:источник
Это не совсем скрыто, но, безусловно, недооцененная функция: scalac -Xprint .
В качестве иллюстрации использования рассмотрим следующий источник:
Компилируем это с помощью scalac -Xprint: typer output :
Обратите внимание
scala.this.Predef.augmentString("xx").r
, что это приложениеimplicit def augmentString
настоящего в Predef.scala.scalac -Xprint: <phase> напечатает синтаксическое дерево после некоторой фазы компилятора. Чтобы увидеть доступные фазы, используйте scalac -Xshow-фазы .
Это отличный способ узнать, что происходит за кулисами.
Попробуй с
case class X(a:Int,b:String)
используя фазу Typer, чтобы действительно почувствовать, насколько это полезно.
источник
Вы можете определить свои собственные структуры управления. На самом деле это просто функции, объекты и некоторый синтаксический сахар, но они выглядят и ведут себя как настоящие.
Например, следующий код определяет
dont {...} unless (cond)
иdont {...} until (cond)
:Теперь вы можете сделать следующее:
источник
zif[A : Zero](cond: => Boolean)(t: => A): A = if(cond) t else mzero
. Требуется Скалаз.@switch
аннотация в Scala 2.8:Пример:
источник
Не знаю, если это действительно скрыто, но я нахожу это довольно хорошим.
Типовые конструкторы, которые принимают 2 параметра типа, могут быть записаны в инфиксной записи
источник
var foo2barConverter: Foo ConvertTo Bar
, порядок параметров типа будет очевиден.В Scala 2.8 введены аргументы по умолчанию и именованные аргументы, что сделало возможным добавление нового метода «copy», который Scala добавляет к классам case. Если вы определите это:
и вы хотите создать новый Foo, который похож на существующий Foo, только с другим значением «n», тогда вы можете просто сказать:
источник
в Scala 2.8 вы можете добавить @specialized к вашим родовым классам / методам. Это создаст специальные версии класса для примитивных типов (расширяющих AnyVal) и сэкономит затраты на ненужный бокс / распаковку:
class Foo[@specialized T]...
Вы можете выбрать подмножество AnyVals:
class Foo[@specialized(Int,Boolean) T]...
источник
Расширяя язык. Я всегда хотел сделать что-то подобное в Java (не смог). Но в Scala я могу иметь:
а затем напишите:
и получить
источник
Вы можете назначить параметр call-by-name (EDITED: он отличается от параметра lazy!) Для функции, и он не будет оцениваться до тех пор, пока не будет использован функцией (EDIT: фактически он будет переоцениваться каждый раз, когда он используемый). Смотрите этот FAQ для деталей
источник
lazy val xx: Bar = x
в вашем методе и с этого момента вы используете толькоxx
.Вы можете использовать
locally
для введения локального блока, не вызывая проблем с выводом точки с запятой.Использование:
locally
определяется в "Predef.scala" как:Будучи встроенным, он не накладывает никаких дополнительных накладных расходов.
источник
Ранняя инициализация:
Вывод:
источник
Вы можете создавать структурные типы с помощью ключевого слова with
источник
синтаксис заполнителя для анонимных функций
Из спецификации языка Scala:
Из изменений языка Scala :
Используя это, вы можете сделать что-то вроде:
источник
Неявные определения, особенно преобразования.
Например, предположим функцию, которая отформатирует входную строку, чтобы соответствовать размеру, заменив середину на «...»:
Вы можете использовать это с любой строкой и, конечно, использовать метод toString для преобразования чего угодно. Но вы также можете написать это так:
И затем, вы можете передать классы других типов, выполнив это:
Теперь вы можете вызвать эту функцию, передав двойную:
Последний аргумент неявный и передается автоматически из-за неявного объявления de. Кроме того, «s» обрабатывается как String внутри sizeBoundedString, поскольку существует неявное преобразование из него в String.
Последствия этого типа лучше определены для необычных типов, чтобы избежать неожиданных преобразований. Вы также можете явно передать преобразование, и оно все равно будет неявно использоваться внутри sizeBoundedString:
Вы также можете иметь несколько неявных аргументов, но тогда вы должны либо передать все из них, либо не передавать ни один из них. Существует также сокращенный синтаксис для неявных преобразований:
Это используется точно так же.
Последствия могут иметь любое значение. Их можно использовать, например, для сокрытия информации библиотеки. Возьмите следующий пример, например:
В этом примере вызов «f» в объекте Y отправит журнал демону по умолчанию, а экземпляр X - демону Daemon X. Но вызов g для экземпляра X отправит журнал явно указанному DefaultDaemon.
Хотя этот простой пример можно переписать с перегрузкой и частным состоянием, для последствий не требуется частное состояние, и его можно привести в контекст с помощью импорта.
источник
Может быть, не слишком скрыто, но я думаю, что это полезно:
Это автоматически сгенерирует метод получения и установки для поля, которое соответствует соглашению бина.
Дальнейшее описание на developerworks
источник
Неявные аргументы в замыканиях.
Аргумент функции может быть помечен как неявный, как и в методах. В пределах объема тела функции неявный параметр видим и имеет право на неявное разрешение:
источник
Создавайте бесконечные структуры данных с помощью Scala
Stream
: http://www.codecommit.com/blog/scala/infinite-lists-for-the-finite-patientисточник
Типы результатов зависят от неявного разрешения. Это может дать вам форму множественной отправки:
источник
foo
использует,a
который должен присутствовать в среде до выполнения этих команд. Я полагаю, вы имели в видуz.perform(x)
.Scala-эквивалент инициализатора двойной скобки Java.
Scala позволяет вам создать анонимный подкласс с телом класса (конструктором), содержащим операторы для инициализации экземпляра этого класса.
Этот шаблон очень полезен при создании основанных на компонентах пользовательских интерфейсов (например, Swing, Vaadin), поскольку он позволяет создавать компоненты пользовательского интерфейса и более кратко объявлять их свойства.
См. Http://spot.colorado.edu/~reids/papers/how-scala-experience-improved-our-java-development-reid-2011.pdf для получения дополнительной информации.
Вот пример создания кнопки Vaadin:
источник
Исключение членов из
import
заявленийПредположим, вы хотите использовать a,
Logger
который содержит aprintln
иprinterr
метод, но вы хотите использовать только один для сообщений об ошибках и оставить старый добрыйPredef.println
для стандартного вывода. Вы могли бы сделать это:но если
logger
также содержит еще двенадцать методов, которые вы хотели бы импортировать и использовать, перечислять их становится неудобно. Вместо этого вы можете попробовать:но это все еще "загрязняет" список импортируемых участников. Введите сверхмощный шаблон:
и это будет правильно делать ™.
источник
require
метод (определенный вPredef
), который позволяет вам определять дополнительные функциональные ограничения, которые будут проверяться во время выполнения. Представьте, что вы разрабатываете еще один клиент для Твиттера, и вам нужно ограничить длину твита до 140 символов. Кроме того, вы не можете опубликовать пустой твит.Теперь вызов post с недопустимым аргументом длины вызовет исключение:
Вы можете написать несколько требований или даже добавить описание к каждому:
Теперь исключения многословны:
Еще один пример здесь .
бонус
Вы можете выполнить действие каждый раз, когда требование не выполняется:
источник
require
не зарезервированное слово Это всего лишь метод, определенный вPredef
.Черты с
abstract override
методами - это особенность Scala, которая не так широко рекламируется, как многие другие. Целью методов сabstract override
модификатором является выполнение некоторых операций и делегирование вызоваsuper
. Затем эти черты должны быть смешаны с конкретными реализациями ихabstract override
методов.Хотя мой пример на самом деле не намного больше, чем AOP для бедняков, я использовал эти Stackable Traits по своему вкусу для создания экземпляров интерпретатора Scala с предопределенным импортом, пользовательскими привязками и классами. В стекируемых Чертах характера позволил создать свой завод по линиям ,
new InterpreterFactory with JsonLibs with LuceneLibs
а затем имеют полезный импорт и сфера varibles для сценариев пользователей.источник