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


402

스칼라 구문에는 많은 기호가 있습니다. 이러한 종류의 이름은 검색 엔진을 사용하여 찾기가 어렵 기 때문에 포괄적 인 목록이 도움이 될 것입니다.

스칼라의 모든 기호는 무엇이며 각각의 기능은 무엇입니까?

특히, 내가 알고 싶습니다에 대한 ->, ||=, ++=, <=, _._, ::,와 :+=.



2
연산자 문자와 영숫자 문자 : stackoverflow.com/questions/7656937/…
Luigi Plinge

1
또한 scalex 나 계단 책에서 찾을 수없는 "연산자"(주로 클래스 이름이 거의 사용되지 않는 메서드)가있는 경우 (예 : "!!") 소스는 akka, scalaz의 스칼라 독일 가능성이 높습니다 and sbt
Gene T

사용 된 클래스 이름의 예 (독일어) >> raichoo.blogspot.com/2010/06/spass-mit-scala-infixtypen.html
Gene T

검색 엔진에 의해 필터링의 문제에 관한 것은 symbolhound.com은 또한 좋은 대안이다
패트릭 Refondini

답변:


526

나는 교수 목적을 위해 연산자를 네 가지 범주나눕니다 .

  • 키워드 / 예약 된 기호
  • 자동으로 가져온 방법
  • 일반적인 방법
  • 구문 설탕 / 조성

따라서 대부분의 카테고리가 질문에 표시되는 것은 운이 좋은 것입니다.

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

이러한 메소드의 대부분의 정확한 의미는 메소드를 정의하는 클래스에 따라 다릅니다. 예를 들어, <=on 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 : 당신은 어디서 그들을 찾을 지 알아야합니다. 또는 실패하면 지수를 살펴보십시오 (현재 2.9.1에서는 고장 났지만 야간에는 가능합니다).

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

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

처음 두 개는 클래스와 단일 객체 만 사용할 수있게합니다. 세 번째 Predef는 객체 자체 이므로 모든 암시 적 변환과 가져온 메소드를 포함 합니다.

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

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

다른 심볼은 암시 적 변환을 통해 사용할 수 있습니다 . implicit해당 수신 태그가 지정된 메소드 를 매개 변수로 메소드를 수신하는 유형의 오브젝트를보십시오. 예를 들면 다음과 같습니다.

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

위의 경우 유형의 객체를 취하는 메소드 를 통해 ->클래스에 정의됩니다. 여기서 동일한 메소드에 대한 제한되지 않은 유형 매개 변수입니다.ArrowAssocany2ArrowAssocAA

일반적인 방법

따라서 많은 기호는 단순히 클래스의 메서드입니다. 예를 들어

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

++ScalaDoc for 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.

1
val c = ex(2)대신에 의미 했습니까 val ex(c) = 2?
Mike Stay

3
@MikeStay 아니, 나는 의미했다 val ex(c) = 2.
Daniel C. Sobral

아, 패턴 일치 구문을 사용하고 있습니다. 감사.
Mike Stay

=>도 수여하고 상태 '이름으로 호출'사이에 사용 : 예에서와 같이 입력 => 지능 '
스티븐 라이트 W.

1
아마도 : / 및 : \ 정말 직관적이지 않은 연산자를 언급해야 할 수도 있습니다. 따라서 map.foldLeft (initialVal)는 (initialVal : / map)과 동일합니다.-: \는 대신 foldRight입니다.
Mr MT

24

스칼라와 다른 언어의 한 가지 (좋은, IMO) 차이점은 거의 모든 문자로 메소드의 이름을 지정할 수 있다는 것입니다.

열거하는 것은 "구두"가 아니라 단순하고 간단한 방법이며, 그 동작은 개체마다 다릅니다 (일부 규칙이 있음).

예를 들어 Scaladoc 문서에서 List를 여기에서 언급 한 몇 가지 방법이 표시됩니다.

명심해야 할 사항 :

  • 또는 에서처럼 A operator+equal B조합이로 변환되는 대부분의 시간A = A operator B||=++= 예 .

  • 끝나는 메소드 :는 올바른 연관성을 가지 A :: B므로 실제로 는임을 의미합니다 B.::(A).

Scala 설명서를 찾아 보면 대부분의 답변을 찾을 수 있습니다. 여기에 참조를 유지하면 노력이 중복되고 빠르게 뒤쳐 질 것입니다. :)


21

일부 기준에 따라 먼저 그룹화 할 수 있습니다. 이 글에서는 밑줄과 오른쪽 화살표를 설명하겠습니다.

_._마침표를 포함합니다. 스칼라의 마침표는 항상 메서드 호출을 나타냅니다 . 따라서 기간 왼쪽에는 수신자가 있고 오른쪽에는 메시지 (방법 이름)가 있습니다. 이제 스칼라 _특별한 상징 입니다. 예를 들어이 블로그 항목은 모두 유스 케이스입니다. 여기에 익명 함수 바로 가기가 있습니다. 즉, 하나의 인수를 취하고 해당 메소드 _를 호출하는 함수의 바로 가기입니다 . 이제는 _유효한 방법이 아니므로 가장 확실하게 보았 _._1거나 이와 비슷한 것, 즉 _._1함수 인수에서 메소드 를 호출하는 것 입니다. _1하려면 _22튜플의 특정 요소를 추출 튜플의 방법이다. 예:

val tup = ("Hallo", 33)
tup._1 // extracts "Hallo"
tup._2 // extracts 33

이제 함수 응용 프로그램 바로 가기의 유스 케이스를 가정하십시오. 정수를 문자열로 매핑하는 맵이 제공됩니다.

val coll = Map(1 -> "Eins", 2 -> "Zwei", 3 -> "Drei")

죄송합니다. 이미 이상한 구두점이 발생했습니다. 오른쪽 화살표 와 유사한 하이픈과 큰 문자 는을 생성하는 연산자입니다 Tuple2. 따라서 (1, "Eins")또는 을 쓰는 결과에는 차이가 없으며 1 -> "Eins", 특히지도 예제와 같은 튜플 목록에서 나중을 쉽게 읽을 수 있습니다. 이것은 ->마술이 아닙니다. 다른 연산자와 마찬가지로 범위 내 에서 객체의 모든 암시 적 변환 이 있기 때문에 사용할 수 있습니다 scala.Predef. 여기서 일어나는 변환은

implicit def any2ArrowAssoc [A] (x: A): ArrowAssoc[A] 

를 생성 ArrowAssoc하는 ->메소드 는 어디에 있습니까 Tuple2? 따라서 1 -> "Eins"실제 전화 Predef.any2ArrowAssoc(1).->("Eins")입니다. 확인. 밑줄 문자가있는 원래 질문으로 돌아갑니다.

// lets create a sequence from the map by returning the
// values in reverse.
coll.map(_._2.reverse) // yields List(sniE, iewZ, ierD)

밑줄은 다음과 같은 코드를 단축시킵니다.

coll.map(tup => tup._2.reverse)

mapMap 의 메소드는 키와 값의 튜플을 함수 인수에 전달합니다. 우리는 값 (문자열)에만 관심이 있기 때문에 _2튜플 의 메소드로 값을 추출합니다 .


+1 나는 그 ->방법 을 이해하는데 어려움을 겪고 있었지만 당신의 문장은 "그래서 결과에 차이가 없다 " (1, "Eins")또는 1 -> "Eins""구문과 그 사용법을 이해하는데 도움이되었다.
Jesse Webb

블로그 입력 링크가 작동하지 않는 경우
still_learning

15

Daniel과 0__의 훌륭한 답변 외에도 Scala 는 일부 기호에 대한 유니 코드 아날로그를 이해 하므로

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

10

관해서 ::서로가 유래 된 표지 엔트리 ::케이스. 요컨대, 헤드 요소와 테일 목록 Lists을 ' consing ' 하여 구성 하는 데 사용됩니다 . 그것은 목록을 나타내는 클래스 이며 추출기로 사용할 수 있지만 가장 일반적으로 목록 의 메소드입니다 . Pablo Fernandez가 지적했듯이 콜론으로 끝나기 때문에 오른쪽 연관입니다 . 즉, 메소드 호출의 수신자는 오른쪽에 있고 연산자의 왼쪽에는 인수가 있습니다. 이렇게 하면 기존 목록에 새 헤드 요소를 추가 하여 consing을 우아하게 표현할 수 있습니다 .

val x = 2 :: 3 :: Nil  // same result as List(2, 3)
val y = 1 :: x         // yields List(1, 2, 3)

이것은

val x = Nil.::(3).::(2) // successively prepend 3 and 2 to an empty list
val y = x.::(1)         // then prepend 1

추출기 객체로 사용하는 방법은 다음과 같습니다.

def extract(l: List[Int]) = l match {
   case Nil          => "empty"
   case head :: Nil  => "exactly one element (" + head + ")"
   case head :: tail => "more than one element"
}

extract(Nil)          // yields "empty"
extract(List(1))      // yields "exactly one element (1)"
extract(List(2, 3))   // yields "more than one element"

이것은 연산자처럼 보이지만 실제로는 또 다른 (더 읽기 쉬운) 작성 방법입니다

def extract2(l: List[Int]) = l match {
   case Nil            => "empty"
   case ::(head, Nil)  => "exactly one element (" + head + ")"
   case ::(head, tail) => "more than one element"
}

이 게시물 에서 추출기에 대한 자세한 내용을 볼 수 있습니다 .


9

<="읽거나" "작거나 같음"과 같습니다. 따라서 <(보다 작습니까?), >(보다 큼?), ==(같음?), !=(같지 않습니까?), <=(보다 작거나 같음) 및 >=(보다 큼 ) 목록의 수학 연산자 입니다. 또는 같습니까?).

이것은해서는 안 혼동=>(A)의 일종 인 이중 오른쪽 화살표 함수 본체로부터 인수 목록을 분리 및 패턴 매칭 (a에서 테스트 조건을 분리하는 데 사용되는 case일치가 발생할 때 실행되는 본체로부터 차단) . 이전 두 답변 에서이 예를 볼 수 있습니다. 먼저, 함수는 다음을 사용합니다.

coll.map(tup => tup._2.reverse)

유형이 생략됨에 따라 이미 약칭되었습니다. 후속 기능은

// function arguments         function body
(tup: Tuple2[Int, String]) => tup._2.reverse

패턴 일치 사용 :

def extract2(l: List[Int]) = l match {
   // if l matches Nil    return "empty"
   case Nil            => "empty"
   // etc.
   case ::(head, Nil)  => "exactly one element (" + head + ")"
   // etc.
   case ::(head, tail) => "more than one element"
}

4
이 혼동을 피하기 위해 오른쪽 이중 화살표 (\ U21D2), 단일 오른쪽 "맵"화살표 (\ U2192) 및 왼쪽 단일 "in"화살표 (\ U2190)에 유니 코드 문자를 사용하기로 결정했습니다. 스칼라는 이것을 지원하지만 잠시 시도하기 전까지는 조금 회의적이었습니다. 이러한 코드 포인트를 시스템의 편리한 키 조합에 바인딩하는 방법을 찾으십시오. OS X에서는 정말 쉬웠습니다.
Connor Doyle

5

현대적인 IDE가 대규모 스칼라 프로젝트를 이해하는 데 중요하다고 생각합니다. 이러한 연산자는 메소드이기도하기 때문에, 지능적으로 생각하면 정의를 Control- 클릭 또는 Control-b하면됩니다.

cons 연산자 (: :)를 마우스 오른쪽 단추로 클릭하고 scala javadoc에서 "이 목록의 시작 부분에 요소를 추가합니다"라고 표시 할 수 있습니다. 사용자 정의 연산자에서는 찾기 어려운 암시 적으로 정의 될 수 있기 때문에 더욱 중요합니다. IDE는 암시 적 정의 위치를 ​​알고 있습니다.


4

다른 훌륭한 답변에 추가하십시오. 스칼라는 종종 비판적인 두 가지 상징 연산자 인 /:( 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 )( _+_ )

2

스칼라는 대부분의 Java 산술 연산자를 상속 합니다. 여기에는 비트 |( 또는 단일 파이프 문자), 비트 및 &비트 배타적 또는 ^논리 (부울) 또는 ||(2 개의 파이프 문자) 및 논리 및 &&. 흥미롭게도 on에 단일 문자 연산자를 사용할 수 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`

이 '더블 체크'를 통해 변경 불가능한 콜렉션을 변경 가능하게 쉽게 교환 할 수 있습니다.

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)

4
PS 부울에 대해 단일 문자 연산자와 이중 문자 연산자를 사용하는 것에는 차이가 있습니다. 전자는 열망하고 (모든 용어는 평가됨), 결과 부울을 알면 후자는 일찍 종료됩니다. true | { println( "Icke" ); true }⇒ 인쇄! true || { println( "Icke" ); true }⇒ 인쇄 하지 않습니다 !
0__
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.