Використання нуля / нічого / одиниці в 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.