611 Stimmen

Was sind die Verwendungsmöglichkeiten eines Unterstrichs in Scala?

Ich habe mir Folgendes angeschaut die Liste der Erhebungen, die am scala-lang.org und bemerkte eine merkwürdige Frage: " Können Sie alle Verwendungen von "_" nennen? ". Können Sie das? Wenn ja, tun Sie es bitte hier. Erläuternde Beispiele sind willkommen.

646voto

Owen Punkte 37648

Mir fallen folgende Beispiele ein

Existenzielle Typen

def foo(l: List[Option[_]]) = ...

Höherwertige Typparameter

case class A[K[_],T](a: K[T])

Ignorierte Variablen

val _ = 5

Ignorierte Parameter

List(1, 2, 3) foreach { _ => println("Hi") }

Ignorierte Namen von Selbsttypen

trait MySeq { _: Seq[_] => }

Wildcard-Muster

Some(5) match { case Some(_) => println("Yes") }

Platzhaltermuster in Interpolationen

"abc" match { case s"a$_c" => }

Sequenzplatzhalter in Mustern

C(1, 2, 3) match { case C(vs @ _*) => vs.foreach(f(_)) }

Wildcard-Einfuhren

import java.util._

Versteckte Einfuhren

import java.util.{ArrayList => _, _}

Verbindungsschreiben an die Betreiber

def bang_!(x: Int) = 5

Zuweisungsoperatoren

def foo_=(x: Int) { ... }

Platzhalter-Syntax

List(1, 2, 3) map (_ + 2)

Werte der Methode

List(1, 2, 3) foreach println _

Umwandlung von Call-by-Name-Parametern in Funktionen

def toFunction(callByName: => Int): () => Int = callByName _

Standard-Initialisierer

var x: String = _   // unloved syntax may be eliminated

Vielleicht gibt es noch andere, die ich vergessen habe!


Ein Beispiel zeigt, warum foo(_) y foo _ sind unterschiedlich:

Dieses Beispiel kommt von 0__ :

trait PlaceholderExample {
  def process[A](f: A => Unit)

  val set: Set[_ => Unit]

  set.foreach(process _) // Error 
  set.foreach(process(_)) // No Error
}

Im ersten Fall, process _ stellt eine Methode dar; Scala nimmt die polymorphe Methode und versucht, sie durch Ausfüllen des Typparameters monomorph zu machen, stellt aber fest, dass es keine Typ die ausgefüllt werden können für A die den Typ (_ => Unit) => ? (Existentiell _ kein Typ ist).

Im zweiten Fall, process(_) ist ein Lambda; wenn man ein Lambda ohne expliziten Argumenttyp schreibt, leitet Scala den Typ aus dem Argument ab, das foreach erwartet, und _ => Unit est ein Typ (wohingegen nur einfache _ nicht), so dass es ersetzt und abgeleitet werden kann.

Dies ist vielleicht das kniffligste Problem in Scala, dem ich je begegnet bin.

Beachten Sie, dass dieses Beispiel in 2.13 kompiliert. Ignorieren Sie es, als ob es underscore zugewiesen wäre.

209voto

Daniel C. Sobral Punkte 290004

Von (meinem Eintrag) in der FAQ , für deren Vollständigkeit ich keine Garantie übernehme (ich habe erst vor zwei Tagen zwei Einträge hinzugefügt):

import scala._    // Wild card -- all of Scala is imported
import scala.{ Predef => _, _ } // Exception, everything except Predef
def f[M[_]]       // Higher kinded type parameter
def f(m: M[_])    // Existential type
_ + _             // Anonymous function placeholder parameter
m _               // Eta expansion of method into method value
m(_)              // Partial function application
_ => 5            // Discarded parameter
case _ =>         // Wild card pattern -- matches anything
val (a, _) = (1, 2) // same thing
for (_ <- 1 to 10)  // same thing
f(xs: _*)         // Sequence xs is passed as multiple parameters to f(ys: T*)
case Seq(xs @ _*) // Identifier xs is bound to the whole matched sequence
var i: Int = _    // Initialization to the default value
def abc_<>!       // An underscore must separate alphanumerics from symbols on identifiers
t._2              // Part of a method name, such as tuple getters
1_000_000         // Numeric literal separator (Scala 2.13+)

Dies ist auch Teil der diese Frage .

96voto

JAiro Punkte 5652

Eine ausgezeichnete Erklärung der Verwendung des Unterstrichs ist Scala _ [Unterstrich] magic .

 def matchTest(x: Int): String = x match {
     case 1 => "one"
     case 2 => "two"
     case _ => "anything other than one and two"
 }

 expr match {
     case List(1,_,_) => " a list with three element and the first element is 1"
     case List(_*)  => " a list with zero or more elements "
     case Map[_,_] => " matches a map with any key type and any value type "
     case _ =>
 }

 List(1,2,3,4,5).foreach(print(_))
 // Doing the same without underscore: 
 List(1,2,3,4,5).foreach( a => print(a))

In Scala, _ wirkt ähnlich wie * in Java beim Importieren von Paketen.

// Imports all the classes in the package matching
import scala.util.matching._

// Imports all the members of the object Fun (static import in Java).
import com.test.Fun._

// Imports all the members of the object Fun but renames Foo to Bar
import com.test.Fun.{ Foo => Bar , _ }

// Imports all the members except Foo. To exclude a member rename it to _
import com.test.Fun.{ Foo => _ , _ }

In Scala wird für alle nicht-privaten Variablen eines Objekts implizit ein Getter und Setter definiert. Der Getter-Name ist derselbe wie der Variablenname und _= für den Namen des Setzers hinzugefügt.

class Test {
    private var a = 0
    def age = a
    def age_=(n:Int) = {
            require(n>0)
            a = n
    }
}

Verwendung:

val t = new Test
t.age = 5
println(t.age)

Wenn Sie versuchen, eine Funktion einer neuen Variablen zuzuweisen, wird die Funktion aufgerufen und das Ergebnis der Variablen zugewiesen. Diese Verwirrung entsteht durch die optionalen geschweiften Klammern beim Methodenaufruf. Wir sollten _ nach dem Funktionsnamen verwenden, um sie einer anderen Variablen zuzuweisen.

class Test {
    def fun = {
        // Some code
    }
    val funLike = fun _
}

37voto

Electric Coffee Punkte 11154

Es gibt eine Verwendung, die alle hier anscheinend vergessen haben...

Anstatt dies zu tun:

List("foo", "bar", "baz").map(n => n.toUpperCase())

Sie können dies einfach tun:

List("foo", "bar", "baz").map(_.toUpperCase())

15voto

swaraj patil Punkte 211

Hier sind einige weitere Beispiele, bei denen _ verwendet wird:

val nums = List(1,2,3,4,5,6,7,8,9,10)

nums filter (_ % 2 == 0)

nums reduce (_ + _)

nums.exists(_ > 5)

nums.takeWhile(_ < 8)

In allen obigen Beispielen steht ein Unterstrich für ein Element in der Liste (bei reduce steht der erste Unterstrich für den Akkumulator)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X