Scala 中的所有语法糖实例是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2662984/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 02:05:41  来源:igfitidea点击:

What are all the instances of syntactic sugar in Scala?

scalasyntactic-sugar

提问by Hymanson Davis

What are all the instances of syntactic sugar in Scala?

Scala 中的所有语法糖实例是什么?

They are hard to search for since most/all of them are purely symbols and are thus hard to search for without knowing the name of the concept.

它们很难搜索,因为它们中的大多数/全部都是纯粹的符号,因此在不知道概念名称的情况下很难搜索。

TODO:

去做:

  • Implicit conversions
  • _syntax for anonymous functions
  • Other things I'm forgetting
  • 隐式转换
  • _匿名函数的语法
  • 我忘记的其他事情

采纳答案by Hymanson Davis

Basics:

基本:

  • a bis equivalent to a.b.
  • a b cis equivalent to a.b(c), except when bends in :. In that case, a b cis equivalent to c.b(a).
  • a(b)is equivalent to a.apply(b)This is why the following definitions for an anonymous functions are identical:

    val square1 = (x: Int) => x*x
    val square2 = new Function1[Int,Int] {
        def apply(x: Int) = x*x
    }
    

    When calling square1(y), you are actually calling square1.apply(y)which square1must have as specified by the Function1trait (or Function2, etc...)

  • a(b) = cis equivalent to a.update(b,c). Likewise, a(b,c) = dis equivalent to a.update(b,c,d)and so on.

  • a.b = cis equivalent to a.b_=(c). When you create a val/varxin a Class/Object, Scala creates the methods xand x_=for you. You can define these yourself, but if you define y_=you mustdefine yor it will not compile, for example:

    scala> val b = new Object{ def set_=(a: Int) = println(a) }
    b: java.lang.Object{def set_=(Int): Unit} = $anon@17e4cec
    
    scala> b.set = 5
    <console>:6: error: value set is not a member of java.lang.Object{def set_=(Int): Unit}
           b.set = 5
             ^
    
    scala> val c = new Object{ def set = 0 ; def set_=(a:Int) = println(a) }
    c: java.lang.Object{def set: Int; def set_=(Int): Unit} = $anon@95a253
    
    scala> c.set = 5
    5
    
  • -acorresponds to a.unary_-. Likewise for +a,~a, and !a.

  • a <operator>= b, where <operator>is some set of special characters, is equivalent to a = a <operator> bonlyif adoesn't have the <operator>=method, for example:

    class test(val x:Int) {
        def %%(y: Int) = new test(x*y)
    }
    
    var a = new test(10)
    a.x // 10
    a %%= 5 // Equivalent to a = a %% 5
    a.x // 50
    
  • a b相当于a.b
  • a b c等价于a.b(c),除非b以 结尾:。在那种情况下,a b c相当于c.b(a)
  • a(b)相当于a.apply(b)这就是为什么一个匿名函数以下定义是相同的:

    val square1 = (x: Int) => x*x
    val square2 = new Function1[Int,Int] {
        def apply(x: Int) = x*x
    }
    

    拨打电话时square1(y),你实际上是在调用square1.apply(y)square1必须由已按规定Function1性状(或者Function2,等...)

  • a(b) = c相当于a.update(b,c)。同样,a(b,c) = d等价于a.update(b,c,d)等等。

  • a.b = c相当于a.b_=(c)。当你创建一个val/varx在类/对象,斯卡拉创建方法xx_=为您服务。您可以自己定义这些,但如果您定义y_=,则必须定义y,否则将无法编译,例如:

    scala> val b = new Object{ def set_=(a: Int) = println(a) }
    b: java.lang.Object{def set_=(Int): Unit} = $anon@17e4cec
    
    scala> b.set = 5
    <console>:6: error: value set is not a member of java.lang.Object{def set_=(Int): Unit}
           b.set = 5
             ^
    
    scala> val c = new Object{ def set = 0 ; def set_=(a:Int) = println(a) }
    c: java.lang.Object{def set: Int; def set_=(Int): Unit} = $anon@95a253
    
    scala> c.set = 5
    5
    
  • -a对应于a.unary_-。同样的+a~a!a

  • a <operator>= b, where<operator>是一些特殊字符集,a = a <operator> ba没有该<operator>=方法时才等效,例如:

    class test(val x:Int) {
        def %%(y: Int) = new test(x*y)
    }
    
    var a = new test(10)
    a.x // 10
    a %%= 5 // Equivalent to a = a %% 5
    a.x // 50
    

回答by Hymanson Davis

Special Classes: Tuples and Symbols

特殊类:元组和符号

As mentioned by Rahul G, tuples and symbols get a slightly special syntax.

正如Rahul G所提到的,元组和符号有一个稍微特殊的语法。

  • Symbols: the syntax 'xis short for Symbol("x")
  • Tuples: (p1,p2,..,pn)is short for a case class Tuplen[T1,T2,..,Tn](p1,p2,..,pn)
  • 符号:语法'x的缩写为Symbol("x")
  • 元组:(p1,p2,..,pn)是案例类的缩写Tuplen[T1,T2,..,Tn](p1,p2,..,pn)

For example, the following two are equivalent.

例如,以下两个是等价的。

val tuple1 = ("Hello",1)
val tuple2 = Tuple2[String,Int]("Hello",1)

回答by IttayD

In addition to Jaxkson's answer:

除了贾克森的回答:

  • type F[A,B]can be used as A F B.
  • type F[A,B]可以用作A F B.

For example:

例如:

type ->[A,B] = (A,B)
def foo(f: String -> String)
  • Using => typein a method definition makes the compiler wrap expressions inside the method call in a function thunk.
  • 使用=> type方法定义使得函数的thunk方法调用内部编译器包表达式。

For example

例如

def until(cond: => Boolean)(body: => Unit) = while(!cond) body

var a = 0
until (a > 5) {a += 1}

回答by Hymanson Davis

Extractors:

提取器:

There are two methods used for extractors, unapplyand unapplySeq. These are used in multiple variable assignments and pattern matching.

提取器有两种方法,unapplyunapplySeq. 这些用于多变量赋值和模式匹配。

  • The first use case is where unapply takes the object it is supposed to match and returns a Booleanbased on whether or not it matches, for example,

    trait Gender
    trait Male extends Gender
    trait Female extends Gender
    object Male extends Male
    object Female extends Female
    class Person(val g: Gender, val age: Int)
    
    object Adult {
        def unapply(p: Person) = p.age >= 18
    }
    
    def check(p: Person) = p match {
        case Adult() => println("An Adult")
        case _ => println("A Child")
    }
    
    //Will print: An Adult since Adult.unapply returns true.
    check(new Person(Female, 18))
    
    //Will print: A Child as it falls through to the _ case.
    check(new Person(Male, 17))
    
  • 第一个用例是 unapply 获取它应该匹配的对象并Boolean根据它是否匹配返回一个,例如,

    trait Gender
    trait Male extends Gender
    trait Female extends Gender
    object Male extends Male
    object Female extends Female
    class Person(val g: Gender, val age: Int)
    
    object Adult {
        def unapply(p: Person) = p.age >= 18
    }
    
    def check(p: Person) = p match {
        case Adult() => println("An Adult")
        case _ => println("A Child")
    }
    
    //Will print: An Adult since Adult.unapply returns true.
    check(new Person(Female, 18))
    
    //Will print: A Child as it falls through to the _ case.
    check(new Person(Male, 17))
    

Honestly, I don't really get the purpose of the above syntax since it can be done almost just as easily by just putting the code in the casestatements. Of course if you have a better example, leave a comment below

老实说,我并没有真正理解上述语法的目的,因为只需将代码放在case语句中就可以轻松完成。当然,如果你有更好的例子,请在下方留言

  • The general case where unapplytakes some fixed-number of parameters and returns either an Option[T]for a single parameter or a Option[(p1,p2,...)]for multiple, i.e. a Tuple with the matched values, for example, continuing from the above code:

    object Person {
        def apply(g: Gender, age: Int) = new Person(g, age)
        def unapply(p: Person) = if(p.age < 0) None else Some((p.g, p.age))
    }
    
    //Using Person.apply as described in the Basics section
    val alice = Person(Female, 30)
    val bob = Person(Male, 25)
    
    //This calls Person.unapply(alice), which returns Some((Female, 30)).
    //alice_gender is assigned Female and alice_age 30.
    val Person(alice_gender, alice_age) = alice
    
    bob match {
        //Calls Person.unapply(bob), but sees that g is Male, so no match.
        case Person(Female, _) => println("Hello ma'am")
        //Calls Person.unapply(bob) and assigns age = bob.age, but it doesn't pass
        //the 'if' statement, so it doesn't match here either.
        case Person(Male, age) if age < 18 => println("Hey dude")
        //So bob falls through to here
        case _ => println("Hello Sir")
    }
    
    Person(Male,-1) match {
        //Person.unapply(Person.apply(Male,-1)) returns None because p.age < 0.
        //Therefore this case will not match.
        case Person(_, _) => println("Hello person")
        //Thus it falls through to here.
        case _ => println("Are you Human?")
    }
    
  • 一般情况下,unapply接受一些固定数量的参数并返回Option[T]单个参数或Option[(p1,p2,...)]多个参数,即具有匹配值的元组,例如,从上面的代码继续:

    object Person {
        def apply(g: Gender, age: Int) = new Person(g, age)
        def unapply(p: Person) = if(p.age < 0) None else Some((p.g, p.age))
    }
    
    //Using Person.apply as described in the Basics section
    val alice = Person(Female, 30)
    val bob = Person(Male, 25)
    
    //This calls Person.unapply(alice), which returns Some((Female, 30)).
    //alice_gender is assigned Female and alice_age 30.
    val Person(alice_gender, alice_age) = alice
    
    bob match {
        //Calls Person.unapply(bob), but sees that g is Male, so no match.
        case Person(Female, _) => println("Hello ma'am")
        //Calls Person.unapply(bob) and assigns age = bob.age, but it doesn't pass
        //the 'if' statement, so it doesn't match here either.
        case Person(Male, age) if age < 18 => println("Hey dude")
        //So bob falls through to here
        case _ => println("Hello Sir")
    }
    
    Person(Male,-1) match {
        //Person.unapply(Person.apply(Male,-1)) returns None because p.age < 0.
        //Therefore this case will not match.
        case Person(_, _) => println("Hello person")
        //Thus it falls through to here.
        case _ => println("Are you Human?")
    }
    

Note:Case classesdo all those apply/unapplydefinitions for you (as well as other stuff) so use them whenver possible to save time and reduce code.

注意:案例类为您完成所有这些apply/unapply定义(以及其他内容),因此请尽可能使用它们以节省时间并减少代码。

  • unapplySeq. This works similarly to unapplyas above, except it must return an Optionof some kind of sequence.
  • unapplySeq. 这unapply与上面的工作方式类似,但它必须返回Option某种序列。

As a quick example,

举个简单的例子,

scala> List.unapplySeq(List(1,2,3))
res2: Some[List[Int]] = Some(List(1, 2, 3))

回答by vadipp

Anonymous functions:

匿名函数:

_ + _is short for (a, b) => a + b

_ + _是简称 (a, b) => a + b

回答by Erik Kaplun

Context bounds desugar into implicitparameters, e.g. consider a function that leverages the Monoidtype class:

上下文将 desugar 绑定到implicit参数中,例如考虑一个利用Monoid类型类的函数:

def suml[T: Monoid](xs: List[T]) = {
  val T = implicitly[Monoid[T]]
  xs.foldLeft(T.mzero)(T.mplus)
}

where the : Monoidpart is a context bound, gets translated to:

其中: Monoid部分是上下文绑定,被翻译为:

def suml[T](xs: List[T])(implicit evidence: Monoid[T]]) = {
  ...
}

therefore the following compiles, too:

因此,以下也编译:

def suml[T: Monoid](xs: List[T]) = {
  val T = evidence
  ...
}