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

发布于 2024-08-29 00:05:08 字数 168 浏览 3 评论 0原文

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

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

TODO:

  • 隐式转换
  • 匿名函数的
  • _ 语法我忘记的其他事情

What are all the instances of syntactic sugar in 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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

往昔成烟 2024-09-05 00:05:08

基础知识:

  • a b 相当于ab
  • ab c 等同于 ab(c),除非 b: 结尾。在这种情况下,ab c 相当于cb(a)
  • a(b) 相当于 a.apply(b) 这就是为什么以下匿名函数的定义是相同的:

    val square1 = (x: Int) => x*x
    val square2 = 新函数1[Int,Int] {
        def apply(x: Int) = x*x
    }
    

    当调用square1(y)时,您实际上是在调用square1.apply(y),其中square1必须具有< code>Function1 特征(或 Function2 等...)

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

  • ab = c 相当于 a.b_=(c)。当您在类/对象中创建 val/var x 时,Scala 会创建方法 x>x_= 为您服务。您可以自己定义这些,但如果您定义y_=,则必须定义y,否则它将无法编译,例如:

    scala> val b = 新对象{ def set_=(a: Int) = println(a) }
    b: java.lang.Object{def set_=(Int): Unit} = $anon$1@17e4cec
    
    标量> b.设置= 5
    :6: 错误: 值集不是 java.lang.Object{def set_=(Int): Unit} 的成员
           b.设置= 5
             ^
    
    标量> val c = 新对象{ def set = 0 ; def set_=(a:Int) = println(a) }
    c: java.lang.Object{def set: Int; def set_=(Int): 单位} = $anon$1@95a253
    
    标量> c.设置= 5
    5
    
  • < code>-a 对应于 a.unary_-。对于 +a~a!a 也是如此。

  • a= b,其中 是一组特殊字符,相当于 a = a; b 如果 a 没有 = 方法,例如:

    类测试(val x:Int) {
        def %%(y: Int) = 新测试(x*y)
    }
    
    var a = 新测试(10)
    斧头 // 10
    a %%= 5 // 相当于 a = a %% 5
    斧头 // 50
    

Basics:

  • a b is equivalent to a.b.
  • a b c is equivalent to a.b(c), except when b ends in :. In that case, a b c is 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 square1 must have as specified by the Function1 trait (or Function2, etc...)

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

  • a.b = c is equivalent to a.b_=(c). When you create a val/var x in a Class/Object, Scala creates the methods x and x_= for you. You can define these yourself, but if you define y_= you must define y or 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$1@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$1@95a253
    
    scala> c.set = 5
    5
    
  • -a corresponds 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> b only if a doesn'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
    
爱的故事 2024-09-05 00:05:08

特殊类:元组和符号

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

  • 符号:语法 'xSymbol("x")
  • 缩写 元组:(p1,p2,..,pn) 是缩写对于案例类 Tuplen[T1,T2,..,Tn](p1,p2,..,pn)

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

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

Special Classes: Tuples and Symbols

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

  • Symbols: the syntax 'x is short for Symbol("x")
  • Tuples: (p1,p2,..,pn) is short for a case class 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)
夜雨飘雪 2024-09-05 00:05:08

除了 Jaxkson 的答案之外:

  • type F[A,B] 可以用作 AF B

例如:

type ->[A,B] = (A,B)
def foo(f: String -> String)
  • 使用 =>;方法定义中的 type 使编译器将表达式包装在函数 thunk 中的方法调用中。

例如

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

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

In addition to Jaxkson's answer:

  • type F[A,B] can be used as A F B.

For example:

type ->[A,B] = (A,B)
def foo(f: String -> String)
  • Using => type in a method definition makes the compiler wrap expressions inside the method call in a function thunk.

For example

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

var a = 0
until (a > 5) {a += 1}
白云不回头 2024-09-05 00:05:08

提取器:

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

  • 第一个用例是 unapply 获取它应该匹配的对象,并根据它是否匹配返回一个 Boolean,例如,

    特质性别
    特征 男性 延伸 性别
    特质 女性 延伸 性别
    对象 Male 扩展 Male
    对象 女性 延伸 女性
    class Person(val g: 性别, val 年龄: Int)
    
    对象成人{
        def unapply(p: Person) = p.age >= 18
    }
    
    def check(p: 人) = p 匹配 {
        案例成人()=> println("一个成年人")
        案例_=> println("一个孩子")
    }
    
    //将打印:An Adult,因为 Adult.unapply 返回 true。
    check(新人(女,18岁))
    
    // 将打印: A Child 落入 _ 情况。
    检查(新人(男性,17岁))
    

老实说,我不'并不能真正理解上述语法的目的,因为只需将代码放入 case 语句中即可轻松完成。当然,如果您有更好的示例,请在下面留言

  • unapply的一般情况采用一些固定数量的参数并返回Option[T]对于单个参数或 Option[(p1,p2,...)] 对于多个参数,即具有匹配值的元组,例如,从上面的代码继续:

    对象人{
        def apply(g: 性别, 年龄: Int) = new Person(g, 年龄)
        def unapply(p: Person) = if(p.age < 0) None else Some((pg, p.age))
    }
    
    //按照“基础知识”部分中的描述使用 Person.apply
    val alice = 人(女, 30)
    val bob = 人(男,25 岁​​)
    
    //这会调用Person.unapply(alice),它返回Some((Female, 30))。
    //alice_gender 被分配为 Female,alice_age 为 30。
    val Person(alice_gender, alice_age) = alice
    
    鲍勃比赛{
        //调用Person.unapply(bob),但看到g是男性,所以不匹配。
        案例人(女,_)=> println("你好女士")
        //调用Person.unapply(bob)并赋值age = bob.age,但是没有通过
        //'if'语句,所以这里也不匹配。
        案例 人(男性,年龄) 如果年龄 < 18=> println("嘿伙计")
        //所以鲍勃掉到了这里
        案例_=> println("先生您好")
    }
    
    人(男,-1)匹配{
        //Person.unapply(Person.apply(Male,-1)) 返回 None 因为 p.age < 0。
        //因此这种情况不会匹配。
        案例人(_,_)=> println("你好,人")
        //因此它就落到了这里。
        案例_=> println("你是人类吗?")
    }
    

注意: 案例类执行所有这些应用/取消应用< /code> 为您定义(以及其他内容),因此请尽可能使用它们以节省时间并减少代码。

  • unapplySeq。这与上面的 unapply 类似,只是它必须返回某种序列的 Option

举个简单的例子,

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

Extractors:

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

  • The first use case is where unapply takes the object it is supposed to match and returns a Boolean based 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))
    

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 case statements. Of course if you have a better example, leave a comment below

  • The general case where unapply takes 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?")
    }
    

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

  • unapplySeq. This works similarly to unapply as above, except it must return an Option of some kind of sequence.

As a quick example,

scala> List.unapplySeq(List(1,2,3))
res2: Some[List[Int]] = Some(List(1, 2, 3))
记忆消瘦 2024-09-05 00:05:08

匿名函数:

_ + _(a, b) => 的缩写。 a+b

Anonymous functions:

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

悍妇囚夫 2024-09-05 00:05:08

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

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

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

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

因此以下内容也可以编译:

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

Context bounds desugar into implicit parameters, e.g. consider a function that leverages the Monoid type class:

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

where the : Monoid part is a context bound, gets translated to:

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

therefore the following compiles, too:

def suml[T: Monoid](xs: List[T]) = {
  val T = evidence$1
  ...
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文