wake-up-neo.com

Was sind alle Verwendungszwecke eines Unterstrichs in Scala?

Ich habe einen Blick auf die Liste der Umfragen von scala-lang.org geworfen und eine merkwürdige Frage festgestellt: " Können Sie alle Verwendungsmöglichkeiten von" _ "nennen? ". Können Sie? Wenn ja, bitte hier. Erklärende Beispiele werden geschätzt.

471
Ivan

Die, an die ich denken kann, sind

Existenzielle Typen

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

Höhere typisierte Parameter

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

Ignorierte Variablen

val _ = 5

Ignorierte Parameter

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

Ignorierte Namen von Eigenarten

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

Wildcard-Muster

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

Platzhaltermuster in Interpolationen

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

Sequenz-Platzhalter in Mustern

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

Wildcard-Importe

import Java.util._

Importe ausblenden

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

Briefe mit Betreibern verbinden

def bang_!(x: Int) = 5

Zuweisungsoperatoren

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

Platzhaltersyntax

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

Methodenwerte

List(1, 2, 3) foreach println _

Call-by-Name-Parameter in Funktionen konvertieren

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

Standardinitialisierer

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

Es kann andere geben, die ich vergessen habe!


Beispiel, warum foo(_) und foo _ unterschiedlich sind:

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 steht process _ für eine Methode. Scala verwendet die polymorphe Methode und versucht, sie durch Eingabe des Typparameters zu monomorph zu machen, stellt jedoch fest, dass kein type für A eingegeben werden kann, der den Typ (_ => Unit) => ? (Existential _ ist kein Typ) enthält. .

Im zweiten Fall ist process(_) ein Lambda; Wenn Sie ein Lambda ohne expliziten Argumenttyp schreiben, schließt Scala den Typ aus dem Argument ab, das foreach erwartet, und _ => Unitist ein Typ (wobei nur _ nicht einfach ist), sodass er ersetzt und abgeleitet werden kann.

Dies könnte die schwierigste Gotcha in Scala sein, die ich je getroffen habe.

Beachten Sie, dass dieses Beispiel in 2.13 kompiliert wird. Ignorieren Sie es, als wäre es dem Unterstrich zugeordnet.

508
Owen

Aus (meinem Eintrag) in der FAQ , die ich sicherlich nicht für die Vollständigkeit garantieren kann (ich habe 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

Dies ist auch Teil von diese Frage .

146

Eine ausgezeichnete Erklärung für die Verwendung des Unterstrichs ist Scala _ [Unterstrich] Magie.

Beispiele:

 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 verhält sich _ beim Importieren von Paketen ähnlich wie * in Java.

// 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 ein Getter und Setter implizit für alle nicht-privaten Variablen eines Objekts definiert. Der Getter-Name stimmt mit dem Variablennamen überein und _= wird für den Setzernamen hinzugefügt.

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

Verwendungszweck:

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

Wenn Sie versuchen, einer neuen Variablen eine Funktion zuzuweisen, wird die Funktion aufgerufen und das Ergebnis der Variablen zugewiesen. Diese Verwirrung tritt aufgrund der optionalen Klammern für den Methodenaufruf auf. Wir sollten _ hinter dem Funktionsnamen verwenden, um ihn einer anderen Variablen zuzuweisen.

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

Es gibt eine Anwendung, die ich sehen kann, dass jeder hier die Liste vergessen zu haben scheint ...

Anstatt dies zu tun:

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

Sie können dies einfach tun:

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

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 (zur Reduzierung des ersten Unterstrichs für den Akkumulator) 

11
swaraj patil

Neben den Verwendungen die JAiro erwähnt hat, gefällt mir diese hier:

def getConnectionProps = {
    ( Config.getHost, Config.getPort, Config.getSommElse, Config.getSommElsePartTwo )
}

Wenn jemand alle Verbindungseigenschaften benötigt, kann er Folgendes tun:

val ( Host, port, sommEsle, someElsePartTwo ) = getConnectionProps

Wenn Sie nur einen Host und einen Port benötigen, können Sie Folgendes tun:

val ( Host, port, _, _ ) = getConnectionProps
10
tolitius
import scala._    // Wild card -- all of Scala is imported

import scala.{ Predef => _, _ } // Exclusion, 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

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

Please check the below link for more details

[https://docs.scala-lang.org/tutorials/FAQ/finding-symbols.html][1]
6

Es gibt ein spezifisches Beispiel, dass "_" verwendet wird:

  type StringMatcher = String => (String => Boolean)

  def starts: StringMatcher = (prefix:String) => _ startsWith prefix

kann gleich sein:

  def starts: StringMatcher = (prefix:String) => (s)=>s startsWith prefix

Die Anwendung von "_" wird in einigen Szenarien automatisch in "(x $ n) => x $ n" konvertiert.

0
Ke.Steve