Хотя вы sould действительно указать, какие JSON сериализации библиотеки вы используете, это в значительной степени гарантирует, что только делает следующее будет работать:
case class Asset(id: Option[Int], description: Option[String]= None, url = "images/" + id.toString+".png")
Учитывая, что url
имеет значение по умолчанию в любом случае, превращая его в параметр не будет отрицательно влиять на ваш код (вы все равно можете сделать Asset(None)
на примере, как и раньше). Единственным недостатком является то, что теперь клиентский код может создать экземпляр Asset
с другим значением для url
, что может и не быть тем, что вы хотите.
Если это так, вам, вероятно, потребуется создать пользовательский формат json для вашего класса Asset
, но, не зная, какую библиотеку сериализации вы используете, я не могу больше помочь в этом отношении.
UPDATE:
Оп, я полностью пропустил тот факт, что значение по умолчанию для url
зависит от другого параметра (id
) (благодаря @Kristian Домагало для замечать). Таким образом, мой вышеприведенный фрагмент не компилируется. Одно простое решение поставить url
во втором списке параметров, как предложено @Kristian Домагала:
case class Asset(id:Option[Int],description:Option[String]=None)(val url:String = "images/" + id.toString+".png")
Но это не может быть идеальным, как это изменило семантику равенства в Asset
(url
не учитывается больше при сравнении экземпляры), а также изменяет синтаксис построения: когда явно указывается значение url
, вам нужно сделать что-то вроде Asset(Some(123))("gfx/myImage.png")
вместо примера Asset(Some(123), url="gfx/myImage.png")
. Если вы можете жить с этими минусами, это, безусловно, самое простое решение.
В противном случае, есть другая работа вокруг: мы можем переопределить Asset.apply
ourselve (вручную):
case class AssetImpl(val id: Option[Int], val description: Option[String], val url: Option[String]) {
override def productPrefix = "Asset"
}
type Asset = AssetImpl
object Asset {
def apply(id: Option[Int], description: Option[String] = None, url: Option[String] = None) = {
new Asset(id, description, url.orElse(id.map("images/" + _ + ".png")))
}
}
Как вы можете видеть, что я превратил url
в Option
со значением по умолчанию None
(избегая предыдущее ошибка компиляции, поскольку она больше не зависит от id
) и в def apply...
Я создаю экземпляр Asset
со значением по умолчанию для url
(здесь я фактически получаю значение id
) id.map("images/" + _ + ".png")
.
Остальное в основном просто шум, чтобы иметь возможность переопределить Asset.apply
: выясняется, что на самом деле вы не можете переопределить фабрику класса case (вы можете добавлять только отдельные перегрузки). Поэтому я переименовал класс как AssetImpl
, добавил псевдоним типа, чтобы никто не заметил (;-)), и создал мой собственный объект Asset
, где я определяю метод apply
(который больше не конфликтует с автогенерированным apply
, потому что это один находится в отдельном объекте AssetImpl
. Я мог бы просто превратить Asset
в стандартный класс (класс без case), но тогда мне нужно было бы переопределить equals
и hashCode
, который я нахожу более раздражающим, учитывая, что он должен поддерживаться при добавлении/удалении поля для класса.
Это не компилируется. Чтобы ссылаться на 'id',' url' нужно было бы объявить во второй группе параметров. Сначала я отклонил ответ, считая, что вторая группа параметров не будет быть выбранным u p через библиотеки сериализации, но оказывается, что Джеркссон действительно сериализует его. Полное объявление должно быть «case class Asset (id: Option [Int]», описание: Option [String] = None) (val url: String = "images /" + id.toString + ".png") '. Наверное, я не думаю, что значение «url» будет тем, что ожидается, учитывая реализацию «Option.toString». –
Спасибо, что указали это, я полностью пропустил зависимость 'url'->' id'. Я обновил свой ответ. –
Спасибо, что ответили. На самом деле я переместил вычисление url вне класса Asset. Я не уверен, что это правильно, чтобы принять ответ, который я не проверил сам. – rvange