some Viewadalah tipe hasil buram seperti yang diperkenalkan oleh SE-0244 dan tersedia di Swift 5.1 dengan Xcode 11. Anda dapat menganggap ini sebagai pengganti generik "terbalik".
Tidak seperti placeholder generik reguler yang dipenuhi oleh penelepon:
protocol P {}
struct S1 : P {}
struct S2 : P {}
func foo<T : P>(_ x: T) {}
foo(S1()) // Caller chooses T == S1.
foo(S2()) // Caller chooses T == S2.
Jenis hasil buram adalah tempat penampung generik implisit puas dengan implementasi , sehingga Anda bisa memikirkan ini:
func bar() -> some P {
return S1() // Implementation chooses S1 for the opaque result.
}
terlihat seperti ini:
func bar() -> <Output : P> Output {
return S1() // Implementation chooses Output == S1.
}
Bahkan, tujuan akhirnya dengan fitur ini adalah untuk memungkinkan pembalikan generik dalam bentuk yang lebih eksplisit ini, yang juga memungkinkan Anda menambahkan batasan, misalnya -> <T : Collection> T where T.Element == Int. Lihat posting ini untuk info lebih lanjut .
Hal utama yang harus diambil dari hal ini adalah bahwa fungsi yang dikembalikan some Padalah yang mengembalikan nilai jenis beton tunggal tertentu yang sesuai P. Mencoba untuk mengembalikan berbagai jenis yang sesuai dalam fungsi menghasilkan kesalahan kompilator:
// error: Function declares an opaque return type, but the return
// statements in its body do not have matching underlying types.
func bar(_ x: Int) -> some P {
if x > 10 {
return S1()
} else {
return S2()
}
}
Karena placeholder generik implisit tidak dapat dipenuhi oleh beberapa tipe.
Ini berbeda dengan fungsi yang dikembalikan P, yang dapat digunakan untuk merepresentasikan keduanya S1 dan S2karena itu merepresentasikan Pnilai kesesuaian yang berubah-ubah :
func baz(_ x: Int) -> P {
if x > 10 {
return S1()
} else {
return S2()
}
}
Oke, jadi manfaat apa yang -> some Pdimiliki tipe hasil buram daripada tipe protokol kembali -> P?
1. Jenis hasil buram dapat digunakan dengan PAT
Keterbatasan protokol saat ini adalah bahwa PATs (protokol dengan tipe terkait) tidak dapat digunakan sebagai tipe aktual. Meskipun ini adalah batasan yang kemungkinan akan diangkat dalam versi bahasa yang akan datang, karena jenis hasil buram secara efektif hanya penampung generik, mereka dapat digunakan dengan PATs hari ini.
Ini berarti Anda dapat melakukan hal-hal seperti:
func giveMeACollection() -> some Collection {
return [1, 2, 3]
}
let collection = giveMeACollection()
print(collection.count) // 3
2. Jenis hasil buram memiliki identitas
Karena tipe hasil buram menegakkan tipe beton tunggal dikembalikan, kompiler tahu bahwa dua panggilan ke fungsi yang sama harus mengembalikan dua nilai dari jenis yang sama.
Ini berarti Anda dapat melakukan hal-hal seperti:
// foo() -> <Output : Equatable> Output {
func foo() -> some Equatable {
return 5 // The opaque result type is inferred to be Int.
}
let x = foo()
let y = foo()
print(x == y) // Legal both x and y have the return type of foo.
Ini legal karena kompiler mengetahui keduanya xdan ymemiliki tipe beton yang sama. Ini merupakan persyaratan penting untuk ==, di mana kedua parameter jenis Self.
protocol Equatable {
static func == (lhs: Self, rhs: Self) -> Bool
}
Ini berarti bahwa ia mengharapkan dua nilai yang sama-sama bertipe sama dengan tipe konformasi beton. Bahkan jika Equatabledapat digunakan sebagai tipe, Anda tidak akan dapat membandingkan dua Equatablenilai kesesuaian yang berubah-ubah satu sama lain, misalnya:
func foo(_ x: Int) -> Equatable { // Assume this is legal.
if x > 10 {
return 0
} else {
return "hello world"
}
}
let x = foo(20)
let y = foo(5)
print(x == y) // Illegal.
Sebagai kompiler tidak dapat membuktikan bahwa dua sewenang-wenang Equatable nilai memiliki tipe beton mendasar yang sama.
Dengan cara yang sama, jika kami memperkenalkan fungsi pengembalian tipe buram lainnya:
// foo() -> <Output1 : Equatable> Output1 {
func foo() -> some Equatable {
return 5 // The opaque result type is inferred to be Int.
}
// bar() -> <Output2 : Equatable> Output2 {
func bar() -> some Equatable {
return "" // The opaque result type is inferred to be String.
}
let x = foo()
let y = bar()
print(x == y) // Illegal, the return type of foo != return type of bar.
Contoh menjadi ilegal karena meskipun keduanya foodan barkembali some Equatable, mereka "membalikkan" penampung generik Output1dan Output2dapat dipenuhi oleh berbagai jenis.
3. Jenis hasil buram menulis dengan penampung generik
Tidak seperti nilai yang diketikkan dengan protokol biasa, tipe hasil buram cocok dengan placeholder generik biasa, misalnya:
protocol P {
var i: Int { get }
}
struct S : P {
var i: Int
}
func makeP() -> some P { // Opaque result type inferred to be S.
return S(i: .random(in: 0 ..< 10))
}
func bar<T : P>(_ x: T, _ y: T) -> T {
return x.i < y.i ? x : y
}
let p1 = makeP()
let p2 = makeP()
print(bar(p1, p2)) // Legal, T is inferred to be the return type of makeP.
Ini tidak akan berhasil jika makePbaru saja kembali P, karena dua Pnilai mungkin memiliki tipe beton dasar yang berbeda, misalnya:
struct T : P {
var i: Int
}
func makeP() -> P {
if .random() { // 50:50 chance of picking each branch.
return S(i: 0)
} else {
return T(i: 1)
}
}
let p1 = makeP()
let p2 = makeP()
print(bar(p1, p2)) // Illegal.
Mengapa menggunakan jenis hasil buram di atas jenis beton?
Pada titik ini Anda mungkin berpikir untuk diri sendiri, mengapa tidak menulis kode saja sebagai:
func makeP() -> S {
return S(i: 0)
}
Nah, penggunaan jenis hasil buram memungkinkan Anda untuk membuat jenis Sdetail implementasi dengan hanya mengekspos antarmuka yang disediakan olehP , memberi Anda fleksibilitas untuk mengubah jenis beton di kemudian hari tanpa melanggar kode apa pun yang tergantung pada fungsi.
Misalnya, Anda dapat mengganti:
func makeP() -> some P {
return S(i: 0)
}
dengan:
func makeP() -> some P {
return T(i: 1)
}
tanpa melanggar kode apa pun yang memanggil makeP().
Lihat bagian Jenis Buram dari panduan bahasa dan proposal evolusi Swift untuk informasi lebih lanjut tentang fitur ini.