scala - operator - 스칼라의 모든 상징 연산자는 무엇을 의미합니까?




scala string operator (6)

스칼라 문법은 많은 심볼을 가지고있다. 이러한 종류의 이름은 검색 엔진을 사용하여 찾기가 어렵 기 때문에 포괄적 인 목록이 도움이됩니다.

스칼라의 모든 심볼은 무엇이며, 각각 무엇을 하는가?

특히, 나는 -> , ||= , ++= , <= , _._ , :: 그리고 :+= 대해 알고 싶습니다.


Scala는 대부분의 Java 산술 연산자를 상속받습니다. 여기에는 bitwise-or | (단일 파이프 문자), bitwise 및 & , bitwise-exclusive-or ^ 및 논리 (부울) 또는 || (두 개의 파이프 문자) 및 논리적 및 && . 흥미롭게도 boolean 에 단일 문자 연산자를 사용할 수 있으므로 java'ish 논리 연산자는 완전히 중복됩니다.

true && true   // valid
true & true    // valid as well

3 & 4          // bitwise-and (011 & 100 yields 000)
3 && 4         // not valid

다른 게시물에서 지적한대로 등호 = 끝나는 호출은 재 할당에 의해 해결됩니다 (해당 이름의 메소드가없는 경우).

var x = 3
x += 1         // `+=` is not a method in `int`, Scala makes it `x = x + 1`

이 'double-check'을 사용하면 변경할 수없는 콜렉션을 쉽게 변경할 수 있습니다.

val m = collection.mutable.Set("Hallo")   // `m` a val, but holds mutable coll
var i = collection.immutable.Set("Hallo") // `i` is a var, but holds immutable coll

m += "Welt" // destructive call m.+=("Welt")
i += "Welt" // re-assignment i = i + "Welt" (creates a new immutable Set)

Scala와 다른 언어들 사이의 (좋은, IMO) 차이점은 거의 모든 문자로 메서드의 이름을 지정할 수 있다는 것입니다.

열거하는 것은 "구두점"이 아니라 단순하고 간단한 방법이며, 따라서 객체의 동작이 객체마다 다릅니다 (일부 규칙이 있지만).

예를 들어 목록대한 Scaladoc 설명서를 확인하면 여기에서 언급 한 몇 가지 방법이 표시됩니다.

명심해야 할 몇 가지 사항 :

  • 대부분의 경우 A operator+equal B 조합은 ||= 또는 ++= 예와 같이 A = A operator B 변환됩니다.

  • 끝나는 메소드는 오른쪽 연관입니다. 이것은 A :: B 가 실제로 B.::(A) 라는 것을 의미합니다.

Scala 문서를 찾아 보시면 대부분의 답변을 찾을 수 있습니다. 여기에 참조를 유지하면 노력이 중복 될 것이고, 빨리 뒤쳐질 것입니다. :)


다니엘과 0__의 멋진 답변에 덧붙여, 스칼라는 Unicode 아날로그를 일부 기호로 이해한다고 말해야합니다.

for (n <- 1 to 10) n % 2 match {
  case 0 => println("even")
  case 1 => println("odd")
}

사람이 글을 쓸 수있다.

for (n ← 1 to 10) n % 2 match {
  case 0 ⇒ println("even")
  case 1 ⇒ println("odd")
}

다른 우수한 답변에 추가하면됩니다. Scala는 종종 두 개의 비판적 기호 연산자 인 /: foldLeft )와 :\ ( foldRight ) 연산자를 제공합니다. 첫 번째는 오른쪽 연관입니다. 따라서 다음 세 문장은 동일합니다.

( 1 to 100 ).foldLeft( 0, _+_ )
( 1 to 100 )./:( 0 )( _+_ )
( 0 /: ( 1 to 100 ) )( _+_ )

이 세 가지가 :

( 1 to 100 ).foldRight( 0, _+_ )
( 1 to 100 ).:\( 0 )( _+_ )
( ( 1 to 100 ) :\ 0 )( _+_ )

저는 교육자를 가르치는 목적으로 네 가지 범주 로 나누었습니다 :

  • 키워드 / 예약 기호
  • 자동으로 가져온 메소드
  • 일반적인 방법
  • 통용 신당 / 조성

다행히도 대부분의 범주는 다음과 같은 질문에서 나타납니다.

->    // Automatically imported method
||=   // Syntactic sugar
++=   // Syntactic sugar/composition or common method
<=    // Common method
_._   // Typo, though it's probably based on Keyword/composition
::    // Common method
:+=   // Common method

대부분의 메소드의 정확한 의미는 클래스를 정의하는 클래스에 따라 다릅니다. 예를 들어, <= 에 대한 Int"보다 작거나 같음"을 의미 합니다. 첫 번째 것, -> , 아래 예를 들어 보겠습니다. :: 아마도 List 정의 된 메소드 일 것입니다. (같은 이름의 객체 일 수도 있지만) :+= 아마도 다양한 Buffer 클래스에 정의 된 메소드 일 것입니다.

그래서, 그들을 보자.

키워드 / 예약 기호

스칼라에는 특별한 기호가 있습니다. 그 중 두 개는 적절한 키워드로 간주되는 반면 다른 키워드는 단지 "예약 된"키워드입니다. 그들은:

// Keywords
<-  // Used on for-comprehensions, to separate pattern from generator
=>  // Used for function types, function literals and import renaming

// Reserved
( )        // Delimit expressions and parameters
[ ]        // Delimit type parameters
{ }        // Delimit blocks
.          // Method call and path separator
// /* */   // Comments
#          // Used in type notations
:          // Type ascription or context bounds
<: >: <%   // Upper, lower and view bounds
<? <!      // Start token for various XML elements
" """      // Strings
'          // Indicate symbols and characters
@          // Annotations and variable binding on pattern matching
`          // Denote constant or enable arbitrary identifiers
,          // Parameter separator
;          // Statement separator
_*         // vararg expansion
_          // Many different meanings

이것들은 모두 언어의 일부이며, 스칼라 명세 (PDF) 자체와 같이 언어를 적절하게 기술하는 텍스트에서 찾을 수 있습니다.

마지막으로 하나 인 밑줄은 특별한 설명이 필요합니다. 왜냐하면 널리 사용되기 때문에 여러 가지 의미가 있기 때문입니다. 다음은 샘플입니다.

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

하지만 아마도 다른 의미를 잊어 버렸을 것입니다.

자동으로 가져온 메소드

따라서 위의 목록에서 찾고있는 심볼을 찾지 못했다면 메소드 또는 메소드의 일부 여야합니다. 그러나 종종 기호를 볼 수 있으며 클래스의 설명서에는 해당 방법이 없습니다. 이 경우 다른 메소드로 하나 이상의 메소드 컴포지션을 보거나 메소드를 범위로 가져 오거나 가져온 암시 적 변환을 통해 사용할 수 있습니다.

이들은 ScalaDoc 에서 여전히 발견 할 수 있습니다 : 당신은 어디에서 그들을 찾아야하는지 알 필요가 있습니다. 그렇지 않으면 index (현재 2.9.1에서 깨졌지만 야간에도 가능합니다).

모든 스칼라 코드에는 3 가지 자동 가져 오기가 있습니다.

// Not necessarily in this order
import _root_.java.lang._      // _root_ denotes an absolute path
import _root_.scala._
import _root_.scala.Predef._

처음 두 클래스는 클래스와 싱글 톤 객체 만 사용할 수 있습니다. Predef 는 객체 자체이기 때문에 세 번째 것은 모든 암시 적 변환과 가져온 메소드를 포함합니다.

Predef 내부를 Predef 몇 가지 기호가 빠르게 표시됩니다.

class <:<
class =:=
object <%<
object =:=

다른 기호는 암시 적 변환을 통해 사용 가능하게됩니다. 메서드를받는 타입의 객체를 매개 변수로받는 implicit 태그가 붙은 메소드를 살펴보십시오. 예 :

"a" -> 1  // Look for an implicit from String, AnyRef, Any or type parameter

위의 경우, ->A 유형 A 오브젝트를 취하는 any2ArrowAssoc 메소드를 통해 ArrowAssoc 클래스에 정의됩니다. 여기서 A 는 동일한 메소드에 대한 제한되지 않은 유형 매개 변수입니다.

일반적인 방법

따라서 많은 심볼은 클래스의 메소드입니다. 예를 들어,

List(1, 2) ++ List(3, 4)

ScalaDoc List 에서 ++ 메소드를 찾을 수 있습니다. 그러나 메서드를 검색 할 때 알아야 할 규칙이 하나 있습니다. 콜론 (:)으로 끝나는 메소드는 왼쪽 대신 오른쪽으로 바인드 합니다 . 즉, 위 메소드 호출은 다음과 같습니다.

List(1, 2).++(List(3, 4))

만약 내가 가지고 있다면, 대신 1 :: List(2, 3) , 그것은 다음과 같습니다 :

List(2, 3).::(1)

따라서 콜론으로 끝나는 메소드를 찾을 때 오른쪽에있는 유형을 찾아야합니다. 예를 들어 다음과 같이 고려하십시오.

1 +: List(2, 3) :+ 4

첫 번째 방법 ( +: :)은 오른쪽에 바인딩되며 List 있습니다. 두 번째 방법 ( :+ )은 일반적인 방법 일 뿐이며 List 다시 바인딩됩니다.

통용 신당 / 조성

그래서, 여기에 방법을 숨길 수있는 몇 가지 구문 설탕이 있습니다 :

class Example(arr: Array[Int] = Array.fill(5)(0)) {
  def apply(n: Int) = arr(n)
  def update(n: Int, v: Int) = arr(n) = v
  def a = arr(0); def a_=(v: Int) = arr(0) = v
  def b = arr(1); def b_=(v: Int) = arr(1) = v
  def c = arr(2); def c_=(v: Int) = arr(2) = v
  def d = arr(3); def d_=(v: Int) = arr(3) = v
  def e = arr(4); def e_=(v: Int) = arr(4) = v
  def +(v: Int) = new Example(arr map (_ + v))
  def unapply(n: Int) = if (arr.indices contains n) Some(arr(n)) else None
}

val Ex = new Example // or var for the last example
println(Ex(0))  // calls apply(0)
Ex(0) = 2       // calls update(0, 2)
Ex.b = 3        // calls b_=(3)
// This requires Ex to be a "val"
val Ex(c) = 2   // calls unapply(2) and assigns result to c
// This requires Ex to be a "var"
Ex += 1         // substituted for Ex = Ex + 1

마지막 방법은 흥미 롭다. 왜냐하면 어떤 상징적 인 방법을 결합해서 그런 식으로 과제와 같은 방법을 형성 할 수 있기 때문이다.

물론 코드에 나타날 수있는 다양한 조합이 있습니다.

(_+_) // An expression, or parameter, that is an anonymous function with
      // two parameters, used exactly where the underscores appear, and
      // which calls the "+" method on the first parameter passing the
      // second parameter as argument.

필자는 대규모 IDE 프로젝트를 이해하는 데있어 현대 IDE가 중요하다고 생각합니다. 이러한 연산자는 메소드이기도하므로 intellij 아이디어에서 나는 정의를 control-click 또는 control-b합니다.

당신은 cons 연산자 (: :)를 오른쪽 클릭하고 "이 목록의 시작 부분에 요소를 추가합니다."라는 스칼라 javadoc에서 제어 할 수 있습니다. 사용자 정의 연산자에서는, 찾기 힘든 암시에 정의 될 수 있기 때문에 이것은 더욱 중요합니다 ... IDE는 암시 적 정의 된 위치를 알고 있습니다.







operators