Scala'da alt çizginin tüm kullanımları nelerdir?


Yanıtlar:


576

Aklıma gelenler

Varoluşçu Türler

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

Daha yüksek tür tipi parametreleri

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

Yok sayılan değişkenler

val _ = 5

Yok sayılan parametreler

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

Kendi türlerinin yoksayılmış adları

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

Joker desenleri

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

İnterpolasyonlarda joker karakter kalıpları

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

Kalıplarda sıra joker karakteri

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

Joker karakterle içe aktarma

import java.util._

İthalatları gizleme

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

Harfleri operatörlere birleştirme

def bang_!(x: Int) = 5

Atama operatörleri

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

Yer tutucu sözdizimi

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

Yöntem değerleri

List(1, 2, 3) foreach println _

Call-by-name parametrelerini işlevlere dönüştürme

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

Varsayılan başlatıcı

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

Unuttuğum başkaları da olabilir!


Neden foo(_)ve foo _farklı olduklarını gösteren örnek :

Bu örnek 0 __'dan gelir :

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

  val set: Set[_ => Unit]

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

İlk durumda, process _bir yöntemi temsil eder; Scala, polimorfik yöntemi alır ve type parametresini doldurarak monomorfik hale getirmeye çalışır, ancak türüA verecek olan doldurulabilecek bir tür olmadığını fark eder (_ => Unit) => ?(Varoluşçu _bir tür değildir).

İkinci durumda, process(_)bir lambda; açık bir bağımsız değişken türüne sahip bir lambda yazarken Scala bağımsız değişkeni bu tür çıkarır foreachbekler ve _ => Unit bir (sadece düz ise bir tür _değildir) bu ikameli ve çıkarılabilir, böylece.

Bu şimdiye kadar karşılaştığım Scala en zor gotcha olabilir.

Bu örneğin 2.13'te derlendiğini unutmayın. Alt çizgiye atanmış gibi yoksay.


4
Ben desen eşleştirme alt çizgi kullanımı altında uygun iki veya üç olduğunu düşünüyorum, ancak noktalama işaretleri için harf birleştirmek için +1! :-)
Daniel C. Sobral

22
val x: Any = _
Giovanni Botta

2
@Owen println _ 'nin kısmen uygulanan bir işlev olduğunu düşünmüyorum. Yer tutucu sözdiziminin başka bir örneği değil mi? Anlam haritası (_ + 2), tıpkı pritnln (_) haritaya benzer bir şeye (x => println (x)) genişlediğinde, haritaya benzer bir şeye (x => x + 2) genişler
Andrew Cassidy

7
@AndrewCassidy Aslında println _ve println(_)farklı. Örneğin, varoluşçu ve polimorfik türleri biraz farklı şekilde ele almaları bakımından bunu görebilirsiniz. Biraz örnek verecek.
Owen

3
@AndrewCassidy Tamam Bir örnek ekledim.
Owen

179

İçinde (benim girişi) Gönderen SSS kesinlikle tam olduğu garanti etmiyoruz, (ben sadece iki gün önce iki girdileri eklendi):

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+)

Bu da bu sorunun bir parçası .


2
Ekleyebilir var i: Int = _veya özel desen eşleştirme durumu val (a, _) = (1, 2)veya özel durum atılır valfor (_ <- 1 to 10) doIt()
huynhjl

1
Ve def f: T; def f_=(t: T)mutable f üyesi oluşturmak için açılan.
huynhjl

Desen eşleme zaten kapsanmıştır ve _yöntem adlarında hile yapılır. Ama, tamam, tamam. Umarım başka biri SSS'yi günceller ... :-)
Daniel C. Sobral

1
Belki bunu özlüyorsun. vertx.newHttpServer.websocketHandler (_. writeXml (html))
angelokh

@ angelokh Bu, listenin beşincisinde yer alan anonim işlev yer tutucu parametresidir.
Daniel C. Sobral

84

Alt çizginin kullanımıyla ilgili mükemmel bir açıklama Scala _ [alt çizgi] büyüsüdür .

Örnekler:

 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))

Scala'da, paketleri içe aktarırken Java'dakine _benzer *.

// 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 => _ , _ }

Scala'da bir alıcı ve ayarlayıcı, bir nesnedeki tüm özel olmayan değişkenler için örtük olarak tanımlanacaktır. Alıcı adı değişken adıyla aynıdır _=ve ayarlayıcı adı için eklenir.

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

Kullanımı:

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

Yeni bir değişkene bir işlev atamaya çalışırsanız, işlev çağrılır ve sonuç değişkene atanır. Bu karışıklık, yöntem çağırma için isteğe bağlı parantez nedeniyle oluşur. İşlev adından sonra _ değerini başka bir değişkene atamak için kullanmalıyız.

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

2
Bu iyi bir açıklama ama hepsine bile sahip değil. Yok sayılan parametreler / değişkenler, harfleri ve noktalama işaretlerini, varoluşçu türleri, daha yüksek tür türlerini içermiyor
Owen

senin List(1,2,3,4,5).foreach(print(_))sadece yapmak için çok daha okunabilir List(1,2,3,4,5).foreach(print), gerçekten alt çizgiye bile ihtiyacın yok, ama sanırım bu sadece bir stil meselesi
Elektrikli Kahve

1
"_", .map, .flatten, .toList işlevli Koleksiyonlarda yer tutucu olarak nasıl çalışır ... Bazen beni yanlış anlamayı sağlar. :(
m0z4rt

34

Buradaki herkesin listeyi unuttuğunu görebildiğim tek bir kullanım var ...

Bunu yapmak yerine:

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

Bunu basitçe yapabilirsiniz:

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

yani _ burada tüm kullanılabilir fonksiyonların bir ad alanı gibi davranır?
Crt

2
@Crt no, bunun için bir stenografi görevi görürn => n
Electric Coffee

2
bu ilk iki cevapta bahsedilen yer tutucu sözdizimi değil mi?
joelb

13

Burada kullanılan bazı örnekler verilmiştir _:

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)

Yukarıdaki tüm örneklerde, bir alt çizgi listedeki bir öğeyi temsil eder (ilk alt çizgiyi azaltmak için akümülatörü temsil eder)


11

JAiro'nun bahsettiği kullanımların yanı sıra , bunu beğendim:

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

Birisi tüm bağlantı özelliklerine ihtiyaç duyarsa şunları yapabilir:

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

Yalnızca bir ana bilgisayara ve bir bağlantı noktasına ihtiyacınız varsa şunları yapabilirsiniz:

val ( host, port, _, _ ) = getConnectionProps

0

"_" İfadesinin kullanılabileceği özel bir örnek vardır:

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

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

Şuna eşit olabilir:

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

Bazı senaryolarda “_” uygulandığında otomatik olarak “(x $ n) => x $ n” ye dönüşür


Herkesin örneğinin bir yineleme unsuru olduğunu hissediyorum, bunun daha düşük seviyeli bir sözdizimi şekeri gibi olduğunu düşünüyorum, lambda özlü dönüşüm dedi
Ke.Steve
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.