2015-09-02 2 views
3

Каким образом функции с побочными эффектами лучше всего обрабатываются для понимания в Scala?Как обеспечить, чтобы ресурс был закрыт для понимания в Scala

У меня есть для понимания, который начинается с создания своего рода ресурса (х) путем вызова функции f1. Этот ресурс имеет близкий -метод, который должен быть назван в конце, но если для постижение не может каким-то образом (если

Так что у нас что-то вроде:.

import scala.util.{Try,Success,Failure} 

trait Resource { 
    def close() : Unit 
} 

// Opens some resource and returns it as Success or returns Failure 
def f1 : Try[Resource] = ... 
def f2 : Try[Resource] = ... 

val res = for { 
    x <- f1 
    y <- f2 
} yield { 
    (x,y) 
} 

Где я должен позвонить метод close? Я могу назвать его в конце понимания для последнего в качестве последнего заявления (z < - x.close), в части yield или после понимания (res._1.close). из них гарантирует, что закрыть вызывается при возникновении ошибки (например, если f2 не работает). С другой стороны, я мог бы отделить

x <- f1 

из-за понимания, как это:

val res = f1 
res match { 
    case Success(x) => { 
    for { 
     y <- f2 
    } 
    x.close 
    } 

    case Failure(e) => ...  
: 

Это обеспечило бы вызов близко, но не очень хороший код. Разве нет более умного и более чистого способа добиться того же?

+1

возможно дубликат [? Какие альтернативы автоматического управления ресурсами существует для Scala] (http://stackoverflow.com/questions/2207425/what-automatic-resource-management -alternatives-exists-for-scala) – jopasserat

ответ

3

Общий шаблон для закрытия ресурсов шаблон кредита:

type Closable = { def close(): Unit } 

def withClosable[B](closable: Closable)(op: Closable => B): B = { 
    try { 
    op(closable) 
    } finally { 
    closable.close() 
    } 
} 

С небольшим рефакторинга вы можете использовать этот шаблон:

import scala.util.{Try,Success,Failure} 

trait Resource { 
    def close() : Unit 
} 

// Opens some resource and returns it as Success or returns Failure 
def f1(res: Resource) : Try[Resource] = ??? 
def f2(res: Resource) : Try[Resource] = ??? 

val f1Resource: Resource = ??? 
val f2Resource: Resource = ??? 

val res = for { 
    x <- withClosable(f1Resource)(f1) 
    y <- withClosable(f2Resource)(f2) 
} yield { 
    (x,y) 
} 

или

import scala.util.{Try,Success,Failure} 

trait Resource { 
    def close() : Unit 
} 

// Opens some resource and returns it as Success or returns Failure 
def f1: Try[Resource] = { 
    val res: Resource = ??? 
    withClosable(res){ ... } 
} 
def f2: Try[Resource] = { 
    val res: Resource = ??? 
    withClosable(res){ ... } 
} 

val res = for { 
    x <- f1 
    y <- f2 
} yield { 
    (x,y) 
} 
6

Когда у меня есть такая проблема я решаю между двумя возможностями:

  1. Использование Scala ARM
  2. Реализовать Loan Pattern на моем (ссылка летуча и может умереть)

В большинстве случаев я предпочитаю собственную реализацию, чтобы избежать дополнительных зависимостей. Вот код займа Шаблон:

def using[A](r : Resource)(f : Resource => A) : A = 
    try { 
     f(r) 
    } finally { 
     r.close() 
    } 

Использование:

using(getResource())(r => 
    useResource(r) 
) 

Так как вам нужно 2 ресурса вам нужно будет использовать этот шаблон дважды:

using(getResource1())(r1 => 
    using(getResource2())(r2 => 
     doYourWork(r1, r2))) 

Вы также можете посмотреть по следующим ответам:

1

Вы можете использовать

https://github.com/jsuereth/scala-arm

Если ваш "ресурс" не реализует java.io.Closeable (или какой-либо другой закрываемый интерфейс, поддерживаемый чем библиотека) вам просто нужно написать неявное преобразование:

implicit def yourEnititySupport[A <: your.closable.Enitity]: Resource[A] = 
    new Resource[A] { 
    override def close(r: A) = r.commit() 
    // if you need custom behavior here 
    override def closeAfterException(r: A, t: Throwable) = r.rollback() 
    } 

И использовать его как это:

import resource._ 

for { 
    a <- managed(your.closable.Enitity()) 
    b <- managed(your.closable.Enitity()) 
} { doSomething(a, b) } 
+0

В моем случае важно, чтобы ресурс оставался открытым, пока все шаги в понимании выполняются и не закрываются до тех пор, пока последний не удастся - или один шаг не выполнен. Мне кажется, что приведенные выше предложения закрывают ресурс после каждого шага. Он должен быть похож на: * открыть ресурс * если преуспеть, выполнить для понимания, где используется ресурс. * Если открытие ресурса не удалось, ничего не делать. * после этого для понимания: закройте ресурс. В случае, если непонимание не подходит, также близко. Надеюсь, это объяснит это. –

+0

Что вы подразумеваете под «каждым шагом»? Предлагаемый код закрывает управляемые ресурсы после выполнения целого блока {doSomething (a, b)}. – Tyth

Смежные вопросы