Використання нуля / нічого / одиниці в Scala


95

Я щойно прочитав: http://oldfashionedsoftware.com/2008/08/20/a-post-about-nothing/

Наскільки я розумію, Nullце риса і єдина її приклад null.

Коли метод приймає аргумент Null, тоді ми можемо передавати йому лише Nullпосилання або nullбезпосередньо, але не будь-яке інше посилання, навіть якщо воно є нулем ( nullString: String = nullнаприклад).

Мені просто цікаво, в яких випадках використання цієї Nullриси може бути корисним. Існує також риса Ніщо, приклади якої я насправді не бачу.


Я насправді не розумію, яка різниця між використанням Nothing та Unit як типу повернення, оскільки обидва не повертають жодного результату, як дізнатись, який із них використовувати, коли у мене є метод, який виконує журналювання, наприклад?


Чи використовуєте ви Unit / Null / Nothing як щось інше, як тип повернення?

Відповіді:


80

Ви використовуєте Ніщо, лише якщо метод ніколи не повертається (тобто він не може нормально завершити повернення, це може викликати виняток). Ніщо ніколи не створюється, і це існує на користь системи типів (цитуючи Джеймса Айрі: "Причина, що Scala має нижній тип, пов'язана з її здатністю виражати дисперсію в параметрах типу." ). Зі статті, на яку ви посилаєтесь:

Ще одне використання Нічого - це тип повернення для методів, які ніколи не повертаються. Це має сенс, якщо ви задумаєтесь. Якщо тип повернення методу - Ніщо, і екземпляр Нічого не існує абсолютно, тоді такий метод ніколи не повинен повертати.

Ваш метод реєстрації поверне Unit. Існує одиниця значення, тому її можна фактично повернути. З документів API :

Одиниця - це підтип Scala.AnyVal. Існує лише одне значення типу Unit, (), і воно не представлене жодним об’єктом у базовій системі виконання. Метод із типом повернення Unit аналогічний методу Java, який оголошено недійсним.


2
Дякую, під "ніколи не повертається" ви маєте на увазі, що дзвінок блокується на невизначений час (для прикладу методу запуску планувальника завдань?)
— Себастьян Лорбер,

3
@Sabastien: він не повертається нормально, він може створити виняток (див. James-iry.blogspot.com/2009/08/… ). якщо виклик блокування закінчується лише видачею винятку, то це буде враховуватися. дякую за питання, це потребувало роз'яснення.
— Nathan Hughes

18

Стаття, яку ви цитуєте, може ввести в оману. NullТипу для сумісності з віртуальною машиною Java і Java , зокрема.

Треба враховувати, що Скала :

  • повністю орієнтована на об’єкти: кожне значення є об’єктом
  • сильно набирається: кожне значення повинно мати тип
  • повинен обробляти nullпосилання на доступ, наприклад, до бібліотек Java та коду

таким чином, стає необхідним визначити тип для nullзначення, який є Nullознакою і має nullєдиним екземпляром.

У Nullтипі немає нічого особливо корисного, якщо ви не є системою типів або не розробляєте на компіляторі. Зокрема, я не бачу жодної розумної причини для визначення Nullпараметра типу для методу, оскільки ви не можете передати нічого, крімnull


це правда, тож зрештою ніякого іншого використання Null не існує?
— Себастьян Лорбер,

@SebastienLorber відредагував відповідь. Насправді я не бачу жодного використання середнього розробника. Можливо, хтось інший може придумати щось корисне.
— pagoda_5b

Дякую за це Якщо ми знаємо причину такого роду речей, ми їх розуміємо, інакше ми їх пам’ятаємо.
— Шрікар

Null корисний, коли у вас є параметр type і, можливо, ви захочете повернути null, як у цьому питанні та відповіді , оскільки ваш відмовлений від використання null у масштабі він рідко виникає, однак у системі типу можуть бути й інші звичаї
— Daniel Carlsson

15

Чи використовуєте ви Unit / Null / Nothing як щось інше, як тип повернення?


Unit можна використовувати так:

def execute(code: => Unit):Unit = {
  // do something before
  code
  // do something after
}

Це дозволяє передавати довільний блок коду, який буде виконаний.


Nullможе використовуватися як нижній тип для будь-якого значення, яке має нульовий статус. Прикладом є такий:

implicit def zeroNull[B >: Null] =
    new Zero[B] { def apply = null }

Nothing використовується у визначенні None

object None extends Option[Nothing]

Це дозволяє вам присвоїти Noneбудь-який тип, Optionоскільки Nothing"розширює" все.

val x:Option[String] = None

Гаразд. Для вашого використання Unit ви могли використовувати загальний тип, щоб виконання могло повернути цей загальний тип, якщо ваш код коду повертає щось інше, ніж unit.
— Себастьян Лорбер,

Як сказав @drexin у коментарі до іншої відповіді, він в основному використовується для позначення побічного ефекту.
— EECOLOR

6

якщо ви використовуєте Nothing, немає чого робити (включаючи консоль друку), якщо ви щось робите, використовуйте тип виводуUnit

object Run extends App {
  //def sayHello(): Nothing = println("hello?")
  def sayHello(): Unit = println("hello?")
  sayHello()
}

... тоді як користуватися Nothing?

trait Option[E]
case class Some[E](value: E) extends Option[E]
case object None extends Option[Nothing]

1
Крім того, Eв Optionмає бути в коваріантному положенні: trait Option[+E]дозволити такі речі, якval x: Option[Int] = None
— vim

5

Я ніколи фактично не використовував Nullтип, але ви використовуєте Unit, де б ви використовували на Java void. Nothingє особливим типом, тому що, як вже згадував Натан, не може бути жодного випадку Nothing. Nothingце так званий нижній тип, що означає, що це підтип будь-якого іншого типу. Це (і параметр контраваріантного типу), чому ви можете додати будь-яке значення Nil- яке є List[Nothing]- і тоді список буде таким типом елементів. Noneтакож якщо типу Option[Nothing]. Кожна спроба отримати доступ до значень всередині такого контейнера призведе до винятку, оскільки це єдиний дійсний спосіб повернення із методу типу Nothing.


дякую, я не знав, що None розширює Option [Нічого]. Це має сенс у деяких узагальненнях, коли підтип може використовувати нічого (я думаю, важко знайти приклад для Null і Unit ...)
— Себастьян Лорбер,

Використовується блок, де виникають побічні ефекти, наприклад, монада вводу-виводу може бути типу IO[Unit]для друку на консолі тощо.
— drexin

Так, ніколи не використовував монаду IO, має сенс використовувати її з Unit (і, можливо, Нічого, якщо це якась операція IO, яка виробляє нескінченний потік?)
— Себастьян Лорбер,

Ні, ніщо там не має сенсу.
— drexin

3

Ніщо часто не використовується неявно. У наведеному нижче коді, інший пункт має тип Нічого , що підклас Boolean (так само як і будь-який інший AnyVal). Таким чином, все призначення придатне для компілятора, хоча речення else насправді нічого не повертає.val b: Boolean = if (1 > 2) false else throw new RuntimeException("error")


1

Ось приклад Nothingз scala.predef:

  def ??? : Nothing = throw new NotImplementedError

Якщо ви незнайомі (а пошукові системи не можуть на ньому шукати), ???це функція заповнення Scala для всього, що ще не реалізовано. Так само, як у Котліна TODO.

Ви можете використовувати той самий трюк під час створення макетних об’єктів: перевизначте невикористані методи за допомогою спеціального notUsedметоду. Перевага відмови ???полягає в тому, що ви не отримаєте попереджень про компіляцію для речей, які ви ніколи не збираєтесь реалізовувати.


0

З точки зору теорії категорій Ніщо не є початковим об'єктом, а Unit - кінцевим об'єктом .

https://en.wikipedia.org/wiki/Initial_and_terminal_objects

Початкові об'єкти також називаються котермінальними або універсальними , а кінцеві - кінцевими .

Якщо об'єкт є і початковим, і кінцевим , він називається нульовим або нульовим об'єктом.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.