2014-01-06 1 views
3

Я определил неявные преобразования в object. Назовем объект Implicits, и в нем есть одно неявное преобразование.Scala: Импортирование неявных преобразований во всех подпакетах некоторого пакета

package com.gmail.naetmul.stackoverflow.app 

object Implicits { 
    implicit def int_to_intEx(x: Int): IntEx = IntEx(x) 
} 

Этот объект привязан к объекту. Я хочу использовать это неявное преобразование в каждом коде в пакете com.gmail.naetmul.stackoverflow.app и всех его подпакетах, например com.gmail.naetmul.stackoverflow.app.something.anything.everything.

Таким образом, я сделал объект упаковки com.gmail.naetmul.stackoverflow.app.

package com.gmail.naetmul.stackoverflow 

package object app { 
    import com.gmail.naetmul.stackoverflow.app.Implicits._ 
} 

Но это не сработало за пределами точного объекта упаковки. Итак, я изменил объект Implicits на trait, и пусть объект пакета расширяет его.

package com.gmail.naetmul.stackoverflow.app 

trait Implicits { 
    implicit def int_to_intEx(x: Int): IntEx = IntEx(x) 
} 
package com.gmail.naetmul.stackoverflow 

import com.gmail.naetmul.stackoverflow.app.Implicits 

package object app extends Implicits { 
    // some code 
} 

Неявное работал в пакете com.gmail.naetmul.stackoverflow.app. Однако он либо работал, либо не работал в подпакетах.

Например)

Файл A.scala

package com.gmail.naetmul.stackoverflow.app.database 

class A { 
    // Here, the implicit conversion did NOT work. 
} 

Файл B.scala

package com.gmail.naetmul.stackoverflow.app 
package database 

class B { 
    // Here, the implicit conversion DID work. 
} 

Так что вопрос:

  1. Должен ли я использовать trait вместо object в этом случае (с использованием объекта пакета, но определенного снаружи)?

  2. Есть ли другой способ использования неявных преобразований в подпакетах? Я имею в виду, импортировать только один раз и использовать их везде. Способ, который работал в B.scala, кажется прекрасным, но инструкция по умолчанию пакета Eclipse похожа на A.scala, поэтому я должен изменить их вручную.

+0

Пакет декларация многострочного в B.scala является способом получить поведение, которое вы хотите. Если вы поместите его на одну строку, например A.scala, вы получите только пакетный объект для этого пакета. Я не верю, что есть другой способ добиться этого. Поэтому я бы подумал, что вы застряли в том, чтобы либо вручную изменить эти объявления, либо убедить Eclipse сделать это. Я использую IntelliJ IDEA и для этого вы можете указать базовый пакет для каждого модуля, и он сделает объявления пакета для любого кода в подпакетах, используя две строки автоматически (один для базы и один для остальных). –

ответ

3

К вопросу 1, это может быть полезно копить implicits в суперкласса, как «LowPriorityImplicits», но это не кажется, использование в данном случае.

На вопрос 2 вложенные пакеты являются обычным способом приведения имплицитов в область видимости. В спецификации 9.2 на «таре» используется волшебная фраза «видимая под их простыми именами».

Но есть несколько стратегий для использования неявного объема.

Я бы предположил из вашего частичного примера, что вы хотите улучшить Int с помощью метода, такого как odd. В этом случае, поставляя отсутствующий член, вы должны предоставить преобразование, как вы это сделали.

Но есть и другие варианты проектирования API.Например:

Дан API:

package goofy 

object API { 
    def api(i: IntEx) = i.odd 
} 

и клиент из API в подпакете:

package goofy.foo.bar.baz 

import org.junit.Test 

class UseIntExTest { 
    import goofy.API._ 
    @Test def usage(): Unit = { 
    assert(api(3)) 
    } 
} 

где вы импортировали API, и вы получите неявную область «для свободно".

Преобразование в объект компаньон:

package goofy 

class IntEx(val i: Int) { 
    def even = i % 2 == 0 
    def odd = !even 
} 

object IntEx { 
    implicit private[goofy] def `enhanced IntEx`(i: Int): IntEx = new IntEx(i) 
} 

Это работает, потому что IntEx ожидаемый тип. Вы также можете использовать параметры типа таким же образом.

Для полноты, чтобы показать, что преобразование ограничивается в подпакеты:

package roofy 

import org.junit.Test 

class BadUsageTest { 
    import goofy.API._ 
    @Test def usage(): Unit = { 
    //assert(api(3)) // DNC 
    } 
} 
Смежные вопросы