나는 Scala playframework tutorial을 통해 길을 가고 있었고 나는이 코드 조각을 보았습니다.
def newTask = Action { implicit request =>
taskForm.bindFromRequest.fold(
errors => BadRequest(views.html.index(Task.all(), errors)),
label => {
Task.create(label)
Redirect(routes.Application.tasks())
}
)
}
그래서 나는 조사하기로 결정 하고이 게시물을 가로 질러왔다 .
나는 아직도 그것을 얻지 못한다.
이것의 차이점은 무엇입니까?
implicit def double2Int(d : Double) : Int = d.toInt
과
def double2IntNonImplicit(d : Double) : Int = d.toInt
명백한 사실 외에 다른 방법 이름이 있습니다.
언제 implicit
, 왜 사용해야 합니까?
답변
아래에서는 암시 적 주요 사용 사례를 설명하지만보다 자세한 내용은 Scala 프로그래밍 관련 장을 참조하십시오 .
암시 적 매개 변수
메소드의 최종 매개 변수 목록은로 표시 될 수 있으며 implicit
이는 값이 호출되는 컨텍스트에서 값을 가져옴 을 의미합니다. 범위 내에 올바른 유형의 암시 적 값이 없으면 컴파일되지 않습니다. 암시 적 값은 단일 값으로 해석되고 충돌을 피해야하므로 유형을 목적에 맞게 지정하는 것이 좋습니다 Int
.
예:
// probably in a library
class Prefixer(val prefix: String)
def addPrefix(s: String)(implicit p: Prefixer) = p.prefix + s
// then probably in your application
implicit val myImplicitPrefixer = new Prefixer("***")
addPrefix("abc") // returns "***abc"
암시 적 변환
컴파일러가 컨텍스트에 대해 잘못된 유형의 표현식을 찾으면 Function
유형을 확인할 수있는 유형 의 내재 된 값을 찾습니다 . 따라서 A
가 필요하고을 찾으면 범위 내에서 B
유형의 암시 적 값을 찾습니다 B => A
( B
및 A
동반자 객체 와 같은 다른 위치도 확인 ). def
s는 Function
객체 로 “eta-expanded”될 수 있기 때문에 implicit def xyz(arg: B): A
의지도 있습니다.
따라서 메소드의 차이점은 implicit
a Double
가 발견되었지만 a Int
가 필요할 때 표시된 메소드가 컴파일러에 의해 삽입된다는 것 입니다.
implicit def doubleToInt(d: Double) = d.toInt
val x: Int = 42.0
와 동일하게 작동합니다
def doubleToInt(d: Double) = d.toInt
val x: Int = doubleToInt(42.0)
두 번째로 변환을 수동으로 삽입했습니다. 처음에는 컴파일러가 자동으로 동일한 작업을 수행했습니다. 왼쪽의 유형 주석으로 인해 변환이 필요합니다.
Play의 첫 번째 스 니펫 관련 :
이 페이지의 작업은 Play 설명서에서 설명 합니다 ( API 문서 참조 ). 사용하고 있습니다
apply(block: (Request[AnyContent]) ⇒ Result): Action[AnyContent]
온 Action
(같은 이름의 형질 컴패니언) 개체.
따라서 함수를 인수로 제공해야하며 이는 형식으로 리터럴로 작성 될 수 있습니다.
request => ...
함수 리터럴에서 앞에있는 부분 =>
은 값 선언이며 implicit
다른 val
선언 과 마찬가지로 원하는 경우 표시 할 수 있습니다 . 여기에, request
하지 않습니다 표시 할 필요가 implicit
이러한 유형의 검사를위한, 그러나 수 있도록 수행하여 암시 적 값으로 사용할 수 함수 내 필요할 수있는 방법에 대한 (물론, 그것은뿐만 아니라 명시 적으로 사용할 수 있습니다) . 이 특정한 경우 Form 클래스 의 bindFromRequest
메서드에 암시적인 인수 가 필요 하기 때문에이 작업이 수행되었습니다 .Request
답변
경고 : 풍자 만화를 신중하게 포함합니다! YMMV …
루이지의 답변 은 완전하고 정확합니다. 이것은 스칼라 프로젝트에서 자주 발생하기 때문에 암시 적을 과도하게 과도하게 과도하게 사용하는 방법에 대한 예제로 약간 확장하는 것 입니다. 실제로는 “Best Practice” 가이드 중 하나에서 찾을 수도 있습니다 .
object HelloWorld {
case class Text(content: String)
case class Prefix(text: String)
implicit def String2Text(content: String)(implicit prefix: Prefix) = {
Text(prefix.text + " " + content)
}
def printText(text: Text): Unit = {
println(text.content)
}
def main(args: Array[String]): Unit = {
printText("World!")
}
// Best to hide this line somewhere below a pile of completely unrelated code.
// Better yet, import its package from another distant place.
implicit val prefixLOL = Prefix("Hello")
}
답변
request
매개 변수를 implicit
다음 과 같이 표시해야하는 이유와시기 :
작업 본문에서 사용할 일부 메서드에는 다음 과 같은 암시 적 매개 변수 목록 이 있습니다. 예를 들어 Form.scala는 메서드를 정의합니다.
def bindFromRequest()(implicit request: play.api.mvc.Request[_]): Form[T] = { ... }
방금 전화를하는 것처럼 당신은 반드시이 통지를하지 않는 myForm.bindFromRequest()
당신은 명시 적으로 암시 인수를 제공 할 필요가 없습니다. 아니요, 요청 인스턴스가 필요한 메소드 호출이 올 때마다 전달할 유효한 후보 오브젝트를 찾도록 컴파일러 를 남겨 둡니다 . 당신이 있기 때문에 할 요청이 가능한, 당신이 오직 할 필요가있는 것으로 표시하는 것입니다 implicit
.
암시 적 으로 사용할 수있는 것으로 명시 적으로 표시합니다 .
당신은 컴파일러가 Play 프레임 워크에서 보낸 요청 객체 ( “request”라는 이름을 주 었으나 “r”또는 “req”만 사용했을 수 있음)를 필요로하는 곳에 “sly” .
myForm.bindFromRequest()
보여? 거기 아니지만, 그것은 이다 거기!
그것은 단지 당신이 (하지만 당신이 필요한 모든 장소에서 수동으로 그것을 슬롯 필요없이 발생 할 수 있습니다 당신이 만약 소원 때문에, 아무리 그것이 표시 않다면, 명시 적으로 통과 implicit
여부) :
myForm.bindFromRequest()(request)
암시 적으로 표시하지 않으면 위의 작업 을 수행해야합니다. 암시 적으로 표시하지 않아도됩니다.
때 당신은 요청을 표시해야합니다 implicit
? Request의 인스턴스를 예상하는 암시 적 매개 변수 목록 을 선언하는 메소드를 사용하는 경우에만 필요합니다 . 그러나 간단하게 유지하려면 요청을 implicit
항상 표시하는 습관을 들일 수 있습니다 . 그렇게하면 아름다운 간결한 코드를 작성할 수 있습니다.
답변
스칼라에서는 암시 적으로 다음 과 같이 작동합니다 .
변환기
매개 변수 값 인젝터
암시 적 사용에는 3 가지 유형이 있습니다.
-
암시 적으로 유형 변환 : 오류 생성 할당을 의도 한 유형으로 변환합니다.
val x : String = “1”
val y : Int = x
문자열 은 Int 의 하위 유형 이 아니므로 2 행에서 오류가 발생합니다. 오류를 해결하기 위해 컴파일러는 묵시적 키워드가 있고 문자열 을 인수로 사용하고 Int를 리턴하는 범위에서 이러한 메소드를 찾습니다 .
그래서
implicit def z(a:String):Int = 2
val x :String = "1"
val y:Int = x // compiler will use z here like val y:Int=z(x)
println(y) // result 2 & no error!
-
암시 적 수신자 변환 : 일반적으로 수신자 호출 오브젝트의 특성 (예 : 메소드 또는 변수. 따라서 수신자가 속성을 호출하려면 해당 속성이 해당 수신자의 클래스 / 객체의 멤버 여야합니다.
class Mahadi{ val haveCar:String ="BMW" }
class Johnny{
val haveTv:String = "Sony"
}
val mahadi = new Mahadi
mahadi.haveTv // Error happening
여기서 mahadi.haveTv 는 오류를 생성합니다. 스칼라 컴파일러는 먼저 hasHv 속성을 mahadi 수신기 로 찾습니다 . 찾을 수 없습니다. 두 번째로 Mahadi 객체 를 인수로 사용하고 Johnny 객체를 반환 하는 암시 적 키워드가 있는 범위의 메소드를 찾습니다 . 그러나 여기에는 없습니다. 따라서 오류가 발생 합니다. 그러나 다음은 괜찮습니다.
class Mahadi{
val haveCar:String ="BMW"
}
class Johnny{
val haveTv:String = "Sony"
}
val mahadi = new Mahadi
implicit def z(a:Mahadi):Johnny = new Johnny
mahadi.haveTv // compiler will use z here like new Johnny().haveTv
println(mahadi.haveTv)// result Sony & no error
-
암시 적 매개 변수 주입 : 메서드를 호출하고 매개 변수 값을 전달하지 않으면 오류가 발생합니다. 스칼라 컴파일러는 다음과 같이 작동합니다-먼저 값을 전달하려고 시도하지만 매개 변수에 대한 직접적인 값은 얻지 않습니다.
def x(a:Int)= a x // ERROR happening
둘째, 매개 변수에 암시 적 키워드가 있으면 범위 에서 동일한 유형 의 값 을 가진 모든 val 을 찾습니다 . 그렇지 않으면 오류가 발생합니다.
def x(implicit a:Int)= a
x // error happening here
이 문제를 해결하기 위해 컴파일러는 매개 변수 a 에 암시 적 키워드 가 있기 때문에 Int 유형의 암시 적 val 을 찾습니다 .
def x(implicit a:Int)=a
implicit val z:Int =10
x // compiler will use implicit like this x(z)
println(x) // will result 10 & no error.
다른 예시:
def l(implicit b:Int)
def x(implicit a:Int)= l(a)
우리는 또한 이렇게 쓸 수 있습니다.
def x(implicit a:Int)= l
때문에 난 갖는 암시 파라미터 와의 범위에 있어서의 X의 신체 ,가 암시 로컬 변수 ( 파라미터 로컬 변수 ) 의 파라미터 인 X 그래서에서 의 X의 본체 방법 에있어서 시그너처 L의 암시 적 인수 값 이며 x 메소드의 로컬 암시 적 변수 (매개 변수)에 의해 암시 적으로 제출됩니다 . a
그래서
def x(implicit a:Int)= l
이 같은 컴파일러에있을 것입니다
def x(implicit a:Int)= l(a)
다른 예시:
def c(implicit k:Int):String = k.toString
def x(a:Int => String):String =a
x{
x => c
}
이 때문에, 에러가 발생할 C 에서 , X = {X> C}는 명시 적 값 통과 인수 또는 암시 적으로 발해야 범위 .
따라서 x 메소드를 호출 할 때 함수 리터럴의 매개 변수를 명시 적 으로 암시 적으로 만들 수 있습니다.
x{
implicit x => c // the compiler will set the parameter of c like this c(x)
}
이것은 Play-Framework의 액션 방법 에 사용되었습니다
in view folder of app the template is declared like
@()(implicit requestHreader:RequestHeader)
in controller action is like
def index = Action{
implicit request =>
Ok(views.html.formpage())
}
요청 매개 변수를 암시 적으로 명시 적으로 언급하지 않은 경우 다음과 같이 작성해야합니다.
def index = Action{
request =>
Ok(views.html.formpage()(request))
}
답변
또한 위의 경우 only one
유형이 인 암시 적 함수 가 있어야합니다 double => Int
. 그렇지 않으면 컴파일러가 혼동되어 올바르게 컴파일되지 않습니다.
//this won't compile
implicit def doubleToInt(d: Double) = d.toInt
implicit def doubleToIntSecond(d: Double) = d.toInt
val x: Int = 42.0
답변
스칼라의 암시 적 매우 기본적인 예.
암시 적 매개 변수 :
val value = 10
implicit val multiplier = 3
def multiply(implicit by: Int) = value * by
val result = multiply // implicit parameter wiil be passed here
println(result) // It will print 30 as a result
참고 : 여기 multiplier
에 함수에 암시 적으로 전달됩니다 multiply
. 함수 호출에 누락 된 매개 변수는 현재 범위에서 유형별로 조회됩니다. 즉, 범위에 Int 유형의 암시 적 변수가 없으면 코드가 컴파일되지 않습니다.
암시 적 변환 :
implicit def convert(a: Double): Int = a.toInt
val res = multiply(2.0) // Type conversions with implicit functions
println(res) // It will print 20 as a result
참고 :multiply
double 값을 전달하는 함수를 호출 하면 컴파일러는 현재 범위에서 변환 암시 적 함수를 찾으려고 시도합니다 .이 함수 는 (As function accept parameter) 로 변환 Int
됩니다 . 암시 적 함수 가 없으면 컴파일러는 코드를 컴파일하지 않습니다. Double
multiply
Int
convert
답변
나는 당신과 똑같은 질문을했고 실제로 몇 가지 간단한 예제로 이해하기 시작한 방법을 공유해야한다고 생각합니다 (일반적인 사용 사례 만 다루고 있습니다).
Scala를 사용하는 일반적인 사용 사례는 두 가지 implicit
입니다.
- 변수에서 사용하기
- 함수에서 사용하기
예는 다음과 같습니다
변수에서 사용하기 . 보시다시피, implicit
키워드가 마지막 매개 변수 목록에서 사용되면 가장 가까운 변수가 사용됩니다.
// Here I define a class and initiated an instance of this class
case class Person(val name: String)
val charles: Person = Person("Charles")
// Here I define a function
def greeting(words: String)(implicit person: Person) = person match {
case Person(name: String) if name != "" => s"$name, $words"
case _ => "$words"
}
greeting("Good morning") // Charles, Good moring
val charles: Person = Person("")
greeting("Good morning") // Good moring
함수에서 사용하기 . 보시다시피 implicit
함수에가 사용되면 가장 가까운 유형 변환 방법이 사용됩니다.
val num = 10 // num: Int (of course)
// Here I define a implicit function
implicit def intToString(num: Int) = s"$num -- I am a String now!"
val num = 10 // num: Int (of course). Nothing happens yet.. Compiler believes you want 10 to be an Int
// Util...
val num: String = 10 // Compiler trust you first, and it thinks you have `implicitly` told it that you had a way to covert the type from Int to String, which the function `intToString` can do!
// So num is now actually "10 -- I am a String now!"
// console will print this -> val num: String = 10 -- I am a String now!
이것이 도움이되기를 바랍니다.