Aku akan melalui efektif scala slide dan ia menyebutkan pada slide 10 untuk tidak pernah menggunakan val
di sifat
untuk anggota abstrak dan menggunakan def
sebagai gantinya. Slide tidak menyebutkan secara rinci mengapa menggunakan abstrak val
di sifat
adalah anti-pola. Saya akan sangat menghargai jika seseorang dapat menjelaskan praktek terbaik di seluruh menggunakan val vs def dalam sifat abstrak metode
A def
dapat dilaksanakan dengan baik dari def
, sebuah val
, yang malas val
atau objek
. Jadi itu's paling abstrak bentuk pendefinisian anggota. Karena ciri-ciri yang biasanya abstrak interface, mengatakan anda ingin val
mengatakan how pelaksanaan harus dilakukan. Jika anda meminta sebuah val
, yang menerapkan kelas tidak dapat menggunakan def
.
A val
diperlukan hanya jika anda membutuhkan stabil identifier, misalnya untuk jalan-tergantung jenis. Yang's sesuatu yang biasanya anda don't perlu.
Bandingkan:
trait Foo { def bar: Int }
object F1 extends Foo { def bar = util.Random.nextInt(33) } // ok
class F2(val bar: Int) extends Foo // ok
object F3 extends Foo {
lazy val bar = { // ok
Thread.sleep(5000) // really heavy number crunching
42
}
}
Jika anda memiliki
trait Foo { val bar: Int }
anda tidak't dapat mendefinisikan F1
atau F3
.
Ok, dan untuk membingungkan anda dan jawaban @om-nom-nom—menggunakan abstrak `val ini dapat menyebabkan inisialisasi masalah:
trait Foo {
val bar: Int
val schoko = bar + bar
}
object Fail extends Foo {
val bar = 33
}
Fail.schoko // zero!!
Ini adalah aplikasi yang jelek masalah yang menurut pendapat pribadi saya harus pergi di masa depan versi Scala dengan memperbaiki itu di compiler, tapi ya, saat ini juga merupakan alasan mengapa seseorang tidak harus menggunakan abstrak `val.
Edit (Jan 2016): Anda diperbolehkan untuk mengganti abstrak val
deklarasi dengan malas val
pelaksanaan, sehingga juga akan mencegah kegagalan inisialisasi.
Saya lebih suka tidak menggunakan val
dalam ciri-ciri karena val deklarasi telah jelas dan non-intuitif urutan inisialisasi. Anda dapat menambahkan sifat untuk yang sudah bekerja hirarki dan itu akan memecahkan semua hal-hal yang bekerja sebelum, lihat topik saya: https://stackoverflow.com/questions/12091689/why-using-plain-val-in-non-final-classes
Anda harus menyimpan semua hal tentang menggunakan val deklarasi dalam pikiran yang akhirnya jalan anda untuk kesalahan.
Tapi ada saat-saat ketika anda tidak bisa menghindari menggunakan val
. Seperti @0__ telah disebutkan kadang-kadang anda perlu stabil pengenal dan def
tidak satu.
Saya akan memberikan contoh untuk menunjukkan apa yang ia bicarakan:
trait Holder {
type Inner
val init : Inner
}
class Access(val holder : Holder) {
val access : holder.Inner =
holder.init
}
trait Access2 {
def holder : Holder
def access : holder.Inner =
holder.init
}
Ini menghasilkan kode kesalahan:
StableIdentifier.scala:14: error: stable identifier required, but Access2.this.holder found.
def access : holder.Inner =
Jika anda mengambil satu menit untuk berpikir anda akan mengerti bahwa compiler memiliki alasan untuk mengeluh. Di Access2.akses
hal itu tidak bisa memperoleh kembali jenis dengan cara apapun. def pemegang
berarti bahwa hal itu bisa diimplementasikan dalam cara yang luas. Itu bisa kembali pemegang berbeda untuk setiap panggilan dan bahwa pemegang akan menggabungkan berbagai Batin
jenis. Tapi Java virtual machine mengharapkan jenis yang sama untuk dikembalikan.
Selalu menggunakan def tampaknya sedikit canggung karena sesuatu seperti ini tidak't bekerja:
trait Entity { def id:Int}
object Table {
def create(e:Entity) = {e.id = 1 }
}
Anda akan mendapatkan error berikut:
error: value id_= is not a member of Entity