2010-06-08 26 views
6

Tôi gặp lỗi lạ khi cố gắng sử dụng bản đồ Java trong Scala. Đây là đoạn mãLỗi chuyển đổi loại Scala, cần trợ giúp!

val value:Double = map.get(name) 
    if (value eq null) map.put(name, time) else map.put(name, value + time) 

bản đồ được định nghĩa là

val map=new ConcurrentHashMap[String,Double] 

và đây là lỗi Tôi nhận

error: type mismatch; 
found : Double 
required: ?{val eq: ?} 
Note that implicit conversions are not applicable because they are ambiguous: 
both method double2Double in object Predef of type (Double)java.lang.Double 
and method doubleWrapper in object Predef of type (Double)scala.runtime.RichDouble 
are possible conversion functions from Double to ?{val eq: ?} 
if (value eq null) map.put(name, time) 

Tôi mới vào Scala vì vậy tôi đang gặp một khó phân tích cú pháp stacktrace. Bất kỳ trợ giúp nào sẽ được đánh giá cao

Trả lời

5

Đầu tiên, map.get(name) sẽ không trả lại null trong trường hợp không có phím name trong bản đồ. Thay vào đó, nó sẽ trả lại một số Double(0.0).

Thứ hai, lỗi mà bạn thấy là do scala đang cố gắng chuyển đổi hoàn toàn giá trị Double đã trả về thành loại phù hợp với so sánh eq và tìm thấy nhiều chuyển đổi tiềm ẩn trong phạm vi.

Cách tốt hơn để làm những gì bạn đang làm là

if (map contains name) map.put(name, map.get(name) + time) 
else map.put(name, time) 
+0

Cảm ơn bạn đã giải thích –

3
error: type mismatch; 
found : Double 
required: ?{val eq: ?} 

Vấn đề ở đây là eq chỉ định cho các lớp học mở rộng AnyRef và mở rộng bởi Null, nhưng Double kéo dài AnyVal để thay thế.

1

Như Daniel đã viết, một phần của sự cố khi cố gắng viết theo kiểu Java với Double xuất phát từ thực tế là Double trong Scala là scala.Double chứ không phải java.lang.Double. Nếu bạn muốn chương trình theo kiểu Java bạn sẽ phải đi dọc theo dòng sau đây:

// 
// a) Java style, with concurrency problem 
// 
import java.lang.{Double=>JDouble} 
import java.util.concurrent.ConcurrentHashMap 
val map = new ConcurrentHashMap[String, JDouble] 
def update(name: String, time: Double) { 
    val value: JDouble = map.get(name) 
    if (value eq null) 
    map.put(name, time) 
    else 
    map.put(name, JDouble.valueOf(value.doubleValue + time)) 
} 
update("foo", 42.0d) 
update("foo", 41.0d) 
assert(map.get("foo") == 83.0d) 

Scala 2.8 chứa một wrapper Scala cho ConcurrentMap s, vì vậy bạn có thể dễ dàng tránh được những vấn đề của java.lang.Double vs scala.Double. Tôi sẽ giữ cấu trúc chương trình trong giây lát.

// 
// b) Scala style, with concurrency problem. 
// 
import collection.JavaConversions._ 
import collection.mutable.ConcurrentMap 
import java.util.concurrent.ConcurrentHashMap 
val map: ConcurrentMap[String, Double] = new ConcurrentHashMap[String,Double]() 
def update(name: String, time: Double) { 
    map.get(name) match { 
    case None => map.put(name, time) 
    case Some(value) => map.put(name, value + time) 
    } 
} 
update("foo", 42.0d) 
update("foo", 41.0d) 
assert(map("foo") == 83.0d) 

Trong biến b) trên đây có không phải là vấn đề đại diện cho các giá trị bị mất tích như 0.0d cũng không phải là vấn đề mà java.lang.Double không chơi độc đáo với các nhà khai thác và boxing. Nhưng cả hai phiên bản a) và b) đều có vấn đề về hành vi tương tranh của chúng. Mã của Mansoor sử dụng ConcurrentHashMap, có mục đích cho phép truy cập đồng thời vào bản đồ. Trong phiên bản gốc của mã, có khả năng một bản cập nhật cho bản đồ bị mất giữa việc lấy value cũ và lưu trữ value + time. Biến thể c) bên dưới cố gắng tránh sự cố đó.

// 
// c) Scala style, hopefully safe for concurrent use ;) 
// 
import collection.JavaConversions._ 
import collection.mutable.ConcurrentMap 
import java.util.concurrent.ConcurrentHashMap 
val map: ConcurrentMap[String, Double] = new ConcurrentHashMap[String,Double]() 

def update(name: String, time: Double) { 
    val valueOption: Option[Double] = map.putIfAbsent(name, time) 
    def replace(value: Double) { 
    val replaced = map.replace(name, value, value + time) 
    if (!replaced) { 
     replace(map(name)) 
    } 
    } 
    valueOption foreach { replace(_) } 
} 

update("foo", 42.0d) 
update("foo", 41.0d) 
assert(map("foo") == 83.0d) 
Các vấn đề liên quan