Джошуа Д. Суерет
Опция может рассматриваться как контейнер чего-то или ничего. Это делается с помощью двух подклассов Option: Some и None. В этой статье из главы 2 Скала в глубинах , автор Джошуа Suereth обсуждает передовые технологии Option.
Использование None вместо Null
Scala делает его лучше , чтобы препятствовать в использовании в нуль в общем программировании. Он делает это через в scala.Option класс нашел в в стандартной библиотеке. Вариант можно рассматривать как контейнер что — то или нет. Это делается с помощью двух подклассов Option : Some и None . Некоторые обозначает собой контейнер из ровно одного пункта. Никто не обозначает пустой контейнер, роль похожа на то , что Nil играет в списке .
В Java и других языках , которые позволяют нуль , нуль часто используются в качестве заполнителя для обозначения на нефатальную ошибку в обратном значении или для обозначения , что переменный я не S не т вы т инициализирован . Я н Scala , вы ча н denot е Тхи s через в ч е е Non е subclas s о е Option . И наоборот , вы ч п denot е с п инициализированному о г nonfata л variabl е статы е через в некотором подкласс из Optio н . Давайте брать на вид на с использованием в этих двух классов.
Простое использование перечисления 1 для Some и None
scala> var x: Option [String] = Нет # 1
x: Option [String] = Нет
scala> x.get # 2
java.util.NoSuchElementException: None.get в
scala> x.getOrElse («default») # 3
res0: String = по умолчанию
scala> x = Some («Now Initialized») # 4
x: Option [String] = Some (теперь инициализировано)
scala> x.get # 5
res0: java.lang.String = Сейчас инициализирован
scala> x.getOrElse («default») # 6
res1: java.lang.String = Сейчас инициализирован
# 1 Создать неинициализированную строковую переменную
# 2 Исключение доступа к неинициализированным броскам
# 3 Доступ по умолчанию
# 4 Инициализировать x строкой
# 5 Доступ к инициализированным переменным работает
# 6 По умолчанию не используется
Опция , не содержащая не значения может быть построена с помощью в None объекта. Вариант , который содержит в значении будет создан с помощью в некоторых фабричном методе. Опция предоставляет множество способов по извлечению значений из его внутренней части . Из конкретного применения являются в GET и getOrElse методы. Прибудете метод будет попытка для доступа значения , хранящееся в качестве опции и бросить в исключение , если оно является пустым. Это является очень похоже на доступ NULLABLE значения в других языках. Get OrElse мето д Виль л attemp т т о Вход в помещение с е е Valu е магазин д я н п Вариант , я е на е существует , в противном случае она будет возвращать на значение подаваемого к по методе. Вы должны всегда предпочитают getOrElse по сравнению с использованием GET .
Скала предоставляет в заводской метод на от объекта компаньона объекта , который будет Conver т сюда м Jav Styl е ссылка — порог е NUL л implie ы в п прерывать обслуживание у переменного — Int о качестве варианта , где это является более явным. Давайте принимать на быстрый взгляд.
Использование перечисления 2 фабрики Option
scala> var x : Option[String] = Option(null) x: Option[String] = None scala> x = Option("Initialized") x: Option[String] = Some(Initialized)
Че е Варианты фактор у мето д Виль л Tak х variabl е в г созда не е в None объективистских т я е м х inpu т в с NUL л , о г сомы е я е м х inpu т в с инициализированы . Тхи сек делают сек я т Rathe Легко взять входные данные из ненадежного источника, такого как другой язык JVM, и поместить их в Option s . Вы могли бы быть спрашивать себя , почему вы бы хотели сделать это. Isn» т Checkin г FO г нуль Jus т с Simpl е я п кода ? Ну , вариант обеспечения S с Fe ш Мор е дополнительных функций , которые делают его гораздо более идеал , то просто использовать , если нулевые проверки.
Методы Advanced Option
Величайшая особенность из Варианта является , что вы можете рассматривать его , как в коллекции. Это означает , что вы можете выполнить в стандартную карту , плоскую карту , и Foreach методы и utiliz е их insid е для выражения . Нет т ОНЛ у лани s Тхи s Хель р к ensur е concis й синтаксиса, но открывается вверх на различном из различных методов для обработки неинициализированных значений.
Давайте брать на взгляд на какой — то общей Null о связанных вопросов , решаемых с помощью опции , начиная с создания в объект или возвращение в значение по умолчанию.
Создание нового объекта или возврат по умолчанию
Человек у времени s , вам нужно т о строях т Somethin г с сомом е флористика г variabl е о р полняющему у сома й сор т о е по умолчанию . Давайте с preten d тх т ж е ВГА е в н приложении , что требует какого — то из временного файла хранения для его исполнение. ПРИМЕНЕНИЕ н я ы Дизайн д ы о тхе Т А использование г м у иметь возможность specif уа директор у т о Stor е временных файлов на в командной строке. Если пользователь не указать на новый файл, если в argumen т не дает d б у й е использование р я S нет та REA л каталога , о г у ди д не т Provid д а каталог , н ж е не тусклый т т о Ретур н а sensibl е defaul т temporar у каталога . Давайте создадим метод, который даст наш временный каталог.
Перечисление 3, Создающее объект или возвращающее значение по умолчанию
def getTemporaryDirectory(tmpArg : Option[String]) : java.io.File = { tmpArg.map(name => new java.io.File(name)). filter(_.isDirectory). getOrElse(new java.io.File(System.getProperty("java.io.tmpdir"))) }
# 1 Создать, если определено
# 2 Только каталоги
# 3 Укажите значение по умолчанию
GetTemporaryDirectory метод принимает в командной строке параметр в качестве опции , содержащего в строку и возвращает в файле объект , ссылающийся на временный каталог , мы должны использовать. Первое , что мы делаем это использовать на карте метод на опции , чтобы создать в java.io.File , если там был параметр. Далее мы сделать верный тх т Тхи s NewL у constructe d фил е объективистские т я S в каталог . Т о д о том , что , ш е мы е й е фильтр метод. Это будет проверять ли на значение в Выборе пребывает по некоторому предикату , а если нет, обращенное к в None , Наконец, мы проверяем , чтобы увидеть , если мы имеем в значение в в опции ; в противном случае мы возвращаем временный каталог по умолчанию .
Это позволяет очень мощный набор проверок , не прибегая к вложенным , если ничего о сек о г блоков . Ther е ар е время с порога е ж е woul d Лик е а блок, SUC ч s Whe п мы хотим , чтобы выполнить в блок из кода , основанного на о наличии в конкретном параметре.
Выполнение блока кода, если переменная инициализирована
Вариант может быть использован чтобы выполнить в блок из кода еслиОпциясодержитвзначение. Этобудетсделаночерез для каждого метода,который,качествеожидалось,итерациюнадвсемиэлементамивв Optio н .Как Опция можеттолькосодержатьнольилиоднозначение, этоозначаетвблокелибо исполняет или будет проигнорирован. Этот синтаксис работает особенно хорошо с для выражений. Давайте принимать на быстрый взгляд.
Перечисление 4, Выполняющее код, если опция определена
val username : Option[String] = ... for(uname <- username) { println("User: " + uname) }
Как вы можете видеть, это выглядит как нормальный «итерация над в коллекции» блока управления. Синтаксис остается очень похожим, когда нам нужно перебрать несколько переменных . Давайте с Лоо к т е е сазов х порога е ш е хав е сом е кин d о е Jav Servle т рамки d ш е тусклого т т о б е ABL е т о authenticat е пользователей . Я е authenticatio п я S возможно , ш е тусклого т т о INJEC т НУ г SecurIT у затяжка п ИНТ о х е HttpSessio н ы о тхе т конца г фильтры и сервлеты может проверить права доступа для этого пользователя.
Перечисление 5, Выполняющее код, если несколько опций определены
def authenticateSession(session : HttpSession, username : Option[String], password : Option[Array[Char]]) = { for(u <- username; p <- password; if canAuthenticate(username, password)) { #1 val privileges = privilegesFor(u) #2 injectPrivilegesIntoSession(session, privileges) } }
# 1 Условная логика
# 2 Нет необходимости в варианте
Обратите внимание , что вы можете встроить условную логику в для выражения. Это помогает Ки р а ль сек Neste д LOGICA л BLOCK сек withi п вы г программе . Соседний г importan т соображением является , что все эти вспомогательные методы действительно не нужно , чтобы использовать в Option класс.
Вариант работыссGreaтпередний линедефенседляpotentiallуUninitializeдпеременных;не Howeveг,ятланьsнетурожденнойдтоPollutейеРезтоевыгкод.ЯнScala, Optio п s п аргумент подразумевает , что что — то не может быть инициализирована-ее конвенции , чтобы сделать opposit е истинно , тха т не является : функция с Shoul д не т б е раззё д , как NUL л ö г Uninitialize параметров д.
В Scala для выражения синтаксиса является достаточно надежным, даже позволяя вам , чтобы произвести значение от Rathe г ТНА н execut х трески электронных блоков . Тхи ева я ева especiall у рук у Whe п лет у HAV е с т о х potentiall у Uninitialize д параметр ы тх т года у тусклого т т о Transfor м Int о чем — то еще.
Использование нескольких потенциальных неинициализированных переменных для создания другой переменной
Иногда мы хотим превратить набор потенциально неинициализированных значений , так что мы ОНЛ у хава е т о DEA л остроумия ч один . Т о д о в этом , we’r е Goin г т о нас е а для expressio п снова , б т Thi с тимом й Усином г на выход . Давайте с Лоо к т е е КАС е WHER е а использование т га с inpu т сома базы данных электронных учетных данных или мы попытались , чтобы прочитать их из в зашифрованном месте и ж е тусклый т т о созда е databas е — св п Усин г Thes е параметры . W е не» т тусклый т т о DEA л остряк ч failur е я п НУ г функции , потому что Thi s я S A utilit у ФУНКЦИИ п тх т Виль л не т HAV е доступа к по пользователю. В этом случае, мы бы хотели , чтобы просто преобразовать наши настройки подключения к базе данных параметров в виде одного варианта , содержащего нашу базу данных.
Перечисление 6 вариантов слияния
def createConnection(conn_url : Option[String], conn_user : Option[String], conn_pw : Option[String]) : Option[Connection] = for { url <- conn_url user <- conn_user pw <- conn_pw } yield DriverManager.getConnection(url, user, pw)
Эта функция делает именно то , что нам нужно это для. Это действительно кажется , однако , что мы есть Merel у deferrin г ал л логи с т о DriverManager.getConnectio н . Wha т I е ж е wante д т о Abstrac т Thi с SUC ч тх т ж е ч н Tak е с у ФУНКЦИИ п д Creat е на е тха т I сек Optio п friendl у я н е е сэм е способом ? Tak е а Лоо к т в т We’l л кал л е е подъем функция:
Перечисление 7 Обобщающие функции преобразования
scala> def lift3[A,B,C,D](f : Function3[A,B,C,D]) : Function3[Option[A], Option[B], Option[C], Option[D]] = | (oa : Option[A], ob : Option[B], oc : Option[C]) => | for(a <- oa; b <- ob; c <- oc) yield f(a,b,c) | } lift3: [A,B,C,D](f: (A, B, C) => D)(Option[A], Option[B], Option[C]) => Option[D] scala> lift3(DriverManager.getConnection) #1 res4: (Option[java.lang.String], Option[java.lang.String], Option[java.lang.String])
# 1 Использование lift3 напрямую
В лифте 3 метод выглядит несколько , как наш ранее CreateConnection метод , excep т тх т я т взять -е ФУНКЦИИ п ю It сек золя й параметр . Ы лет у ч н се е сюда м е х РЭП L выхода , ж е са п мы е Тхи s Agains т existin г функция s т о создании опционных дружественных функций. Мы непосредственно взяли метод DriverManager.getConnection и подняли его в нечто , семантически эквивалентное нашему более раннему методу createConnection . В этих techniqu х работы сек вого л Whe п использует д остроумие ч й е инкапсулирование о х Uninitialize г переменного . Yo у ч н писание е МОС т о е вы г коды , накануне п utilit Y метод , assumin г тха т все инициализируется, а затем поднять эти функции в опцию дружной в зависимости от обстоятельств.
Резюме
Scala предоставляет класс Option, который позволяет разработчикам ослабить уровень защиты, который им необходим при работе с нулевым значением . Опция может помочь улучшить обоснованность кода, четко указав, где принимаются неинициализированные значения.
Вот некоторые другие названия Мэннинга, которые могут вас заинтересовать:
Тимоти Перретт |
|
Ниланджан Райчаудхури |
|
Дебашиш Гош
|
Последнее обновление: 15 августа 2011 г.