Usi di Null / Nothing / Unit in Scala

Ho appena letto: http://oldfashionedsoftware.com/2008/08/20/a-post-about-nothing/

Per quanto ho capito, Null è un tratto e la sua unica istanza è null .

Quando un metodo accetta un argomento Null, possiamo solo passargli un riferimento Null o null direttamente, ma non qualsiasi altro riferimento, anche se è null ( nullString: String = null per esempio).

Mi chiedo solo in quali casi utilizzare questo tratto Null potrebbe essere utile. C’è anche il tratto Nothing per il quale non vedo altri esempi.


Non capisco bene quale sia la differenza tra l’utilizzo di Nothing e Unit come tipo di ritorno, poiché entrambi non restituiscono alcun risultato, come sapere quale utilizzare quando ho un metodo che esegue la registrazione, ad esempio?


Avete usi di Unit / Null / Nothing come qualcosa di diverso da un tipo di ritorno?

Usi Nothing solo se il metodo non ritorna mai (il che significa che non può completare normalmente restituendo, potrebbe generare un’eccezione). Nulla è mai istanziato ed è lì a beneficio del sistema di tipi (per citare James Iry: “La ragione per cui Scala ha un tipo di fondo è legata alla sua capacità di esprimere la varianza nei parametri di tipo.” ). Dall’articolo che hai collegato a:

Un altro uso di Nothing è un tipo di ritorno per i metodi che non ritornano mai. Ha senso se ci pensi. Se il tipo restituito da un metodo è Nothing e non esiste assolutamente alcuna istanza di Nothing, tale metodo non deve mai restituire.

Il tuo metodo di registrazione restituirà l’unità. Esiste un’unità di valore in modo che possa essere effettivamente restituita. Dai documenti API :

L’unità è un sottotipo di scala.AnyVal. Esiste un solo valore di tipo Unit, () e non è rappresentato da alcun object nel sistema runtime sottostante. Un metodo con tipo di ritorno Unit è analogo a un metodo Java dichiarato vuoto.

L’articolo che citi può essere fuorviante. Il tipo Null è lì per la compatibilità con la macchina virtuale Java e, in particolare, con Java.

Dobbiamo considerare che Scala :

  • è completamente orientato agli oggetti: ogni valore è un object
  • è fortemente digitato: ogni valore deve avere un tipo
  • ha bisogno di gestire riferimenti null per accedere, ad esempio, alle librerie e al codice Java

quindi diventa necessario definire un tipo per il valore null , che è il tratto Null , e ha null come sua unica istanza.

Non c’è nulla di particolarmente utile nel tipo Null meno che tu non sia il sistema di tipi o lo sviluppo del compilatore. In particolare non riesco a vedere alcun motivo ragionevole per definire un parametro di tipo Null per un metodo, dal momento che non è ansible passare nulla ma null

Avete usi di Unit / Null / Nothing come qualcosa di diverso da un tipo di ritorno?


Unit può essere utilizzata in questo modo:

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

Ciò consente di passare un blocco di codice arbitrario da eseguire.


Null potrebbe essere usato come un tipo di fondo per qualsiasi valore che è nullable. Un esempio è questo:

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

Nothing viene utilizzato nella definizione di None

 object None extends Option[Nothing] 

Ciò consente di assegnare un None a qualsiasi tipo di Option perché Nothing “estende” tutto.

 val x:Option[String] = None 

Non ho mai effettivamente usato il tipo Null , ma tu usi Unit , dove dovresti usare void su java. Nothing è un tipo speciale, perché come già detto da Nathan, non può esserci istanza di Nothing . Nothing è un cosiddetto tipo di fondo, il che significa che è un sottotipo di qualsiasi altro tipo. Questo (e il parametro di tipo controvariante) è il motivo per cui è ansible anteporre qualsiasi valore a Nil – che è un List[Nothing] – e l’elenco sarà quindi di questo tipo di elementi. None anche se di tipo Option[Nothing] . Ogni tentativo di accedere ai valori all’interno di tale contenitore genererà un’eccezione, poiché è l’unico modo valido per tornare da un metodo di tipo Nothing .

se si utilizza Nothing , non c’è nulla da fare (includere la console di stampa) se si fa qualcosa, utilizzare l’ Unit tipo output

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

… allora come usare Nothing ?

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

Niente è spesso usato implicitamente. Nel seguente codice, val b: Boolean = if (1 > 2) false else throw new RuntimeException("error") la clausola else è di tipo Nothing , che è una sottoclass di Boolean (come qualsiasi altra AnyVal). Pertanto, l’intero compito è valido per il compilatore, sebbene la clausola else non restituisca realmente nulla.

Ecco un esempio di Nothing di scala.predef :

  def ??? : Nothing = throw new NotImplementedError 

Nel caso in cui tu non sia familiare (e i motori di ricerca non possono cercare su di esso) ??? è la funzione segnaposto di Scala per tutto ciò che non è ancora stato implementato. Proprio come Kotlin’s TODO .

Puoi usare lo stesso trucco quando crei oggetti finti: sovrascrivi i metodi non utilizzati con un metodo personalizzato notUsed utilizzato. Il vantaggio di non usare ??? è che non riceverai avvisi di compilazione per cose che non hai intenzione di implementare.