Từ khóa `some` trong Swift (UI) là gì?


259

Hướng dẫn SwiftUI mới có mã sau:

struct ContentView: View {
    var body: some View {
        Text("Hello World")
    }
}

Dòng thứ hai của từ somevà trên trang web của họ được tô sáng như thể đó là một từ khóa.

Swift 5.1 dường như không có sometừ khóa và tôi không thấy từ nào khác somecó thể được thực hiện ở đó, vì nó đi theo kiểu thường đi. Có phiên bản mới, không báo trước của Swift không? Đây có phải là một chức năng đang được sử dụng trên một loại theo cách mà tôi không biết về?

Từ khóa somelàm gì?


Đối với những người bị chóng mặt bởi chủ đề này, đây là một bài viết rất giải mã và từng bước nhờ vào bài viết của Vadim Bulavin. vadimbulavin.com/ từ
Luc-Olivier

Câu trả lời:


333

some Viewloại kết quả mờ đục như được giới thiệu bởi SE-0244 và có sẵn trong Swift 5.1 với Xcode 11. Bạn có thể nghĩ đây là một trình giữ chỗ chung "ngược".

Không giống như một trình giữ chỗ chung thông thường được người gọi hài lòng:

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.

Một loại kết quả mờ đục là một giữ chỗ chung chung được thỏa mãn bởi việc triển khai , vì vậy bạn có thể nghĩ về điều này:

func bar() -> some P {
  return S1() // Implementation chooses S1 for the opaque result.
}

như thế này:

func bar() -> <Output : P> Output {
  return S1() // Implementation chooses Output == S1.
}

Trên thực tế, mục tiêu cuối cùng với tính năng này là cho phép các tổng quát ngược ở dạng rõ ràng hơn này, điều này cũng sẽ cho phép bạn thêm các ràng buộc, ví dụ -> <T : Collection> T where T.Element == Int. Xem bài đăng này để biết thêm .

Điều quan trọng để lấy đi từ này là một hàm trả về some Plà một trong đó trả về một giá trị của một cụ đơn kiểu dữ liệu cụ để tuân thủ P. Cố gắng trả về các loại tuân thủ khác nhau trong hàm dẫn đến lỗi trình biên dịch:

// 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()
  }
}

Vì giữ chỗ chung ẩn có thể được thỏa mãn bởi nhiều loại.

Điều này trái ngược với một hàm trả về P, có thể được sử dụng để biểu diễn cả hai S1S2bởi vì nó đại diện cho một Pgiá trị tuân thủ tùy ý :

func baz(_ x: Int) -> P {
  if x > 10 {
    return S1()
  } else {
    return S2()
  }
}

Được rồi, vì vậy những lợi ích nào làm cho loại kết quả mờ -> some Pcó các loại trả về giao thức-> P ?


1. Các loại kết quả mờ có thể được sử dụng với PAT

Một hạn chế chính hiện tại của các giao thức là các PAT (giao thức với các loại liên quan) không thể được sử dụng như các loại thực tế. Mặc dù đây là một hạn chế có thể sẽ được gỡ bỏ trong phiên bản tương lai của ngôn ngữ, bởi vì các loại kết quả mờ đục thực sự chỉ là các trình giữ chỗ chung chung, chúng có thể được sử dụng với các PAT ngày hôm nay.

Điều này có nghĩa là bạn có thể làm những việc như:

func giveMeACollection() -> some Collection {
  return [1, 2, 3]
}

let collection = giveMeACollection()
print(collection.count) // 3

2. Các loại kết quả mờ có bản sắc

Vì các loại kết quả mờ thực thi một loại bê tông duy nhất được trả về, trình biên dịch biết rằng hai lệnh gọi đến cùng một hàm phải trả về hai giá trị cùng loại.

Điều này có nghĩa là bạn có thể làm những việc như:

//   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.

Điều này là hợp pháp vì trình biên dịch biết rằng cả hai xycó cùng loại cụ thể. Đây là một yêu cầu quan trọng đối với ==, trong đó cả hai tham số của loại Self.

protocol Equatable {
  static func == (lhs: Self, rhs: Self) -> Bool
}

Điều này có nghĩa là nó mong đợi hai giá trị là cùng loại với loại phù hợp cụ thể. Ngay cả khi Equatablecó thể sử dụng như một loại, bạn sẽ không thể so sánh hai Equatablegiá trị tuân thủ tùy ý với nhau, ví dụ:

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.

Vì trình biên dịch không thể chứng minh rằng hai Equatablegiá trị tùy ý có cùng loại bê tông cơ bản.

Theo cách tương tự, nếu chúng tôi giới thiệu một hàm trả về loại mờ khác:

//   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.

Ví dụ trở nên bất hợp pháp vì mặc dù cả hai foobartrả về some Equatable, các trình giữ chỗ chung "ngược" của chúng Output1Output2có thể được thỏa mãn bởi các loại khác nhau.


3. Các loại kết quả mờ kết hợp với giữ chỗ chung

Không giống như các giá trị gõ giao thức thông thường, các loại kết quả mờ kết hợp tốt với các trình giữ chỗ chung thông thường, ví dụ:

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.

Điều này sẽ không hoạt động nếu makePvừa trả về P, vì hai Pgiá trị có thể có các loại cụ thể cơ bản khác nhau, ví dụ:

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.

Tại sao sử dụng loại kết quả mờ trên loại bê tông?

Tại thời điểm này, bạn có thể nghĩ cho chính mình, tại sao không viết mã như sau:

func makeP() -> S {
  return S(i: 0)
}

Chà, việc sử dụng loại kết quả mờ cho phép bạn tạo loại Schi tiết triển khai bằng cách chỉ hiển thị giao diện được cung cấp bởiP , cho phép bạn linh hoạt thay đổi loại cụ thể sau khi xuống dòng mà không phá vỡ bất kỳ mã nào phụ thuộc vào chức năng.

Ví dụ: bạn có thể thay thế:

func makeP() -> some P {
  return S(i: 0)
}

với:

func makeP() -> some P { 
  return T(i: 1)
}

mà không phá vỡ bất kỳ mã nào gọi makeP().

Xem phần Opaque Type của hướng dẫn ngôn ngữ và đề xuất tiến hóa Swift để biết thêm thông tin về tính năng này.


20
Không liên quan: Kể từ Swift 5.1, returnkhông bắt buộc trong các hàm biểu thức đơn
ielyamani

3
Nhưng sự khác biệt giữa: func makeP() -> some Pvà là func makeP() -> Pgì? Tôi đã đọc đề xuất và không thể thấy sự khác biệt này cho các mẫu của họ.
Artem


2
Xử lý loại swifts là một mớ hỗn độn. Là tính đặc hiệu này thực sự là một cái gì đó không thể được xử lý tại thời gian biên dịch? Xem C # để tham khảo, nó xử lý tất cả các trường hợp này thông qua cú pháp đơn giản. Các ca làm việc cần phải có cú pháp rõ ràng gần như vô nghĩa hóa hàng hóa thực sự gây khó chịu cho ngôn ngữ. Bạn cũng có thể giải thích lý do thiết kế cho điều này xin vui lòng? (Nếu bạn có một liên kết đến đề xuất trong github cũng sẽ tốt) Chỉnh sửa: Chỉ cần chú ý rằng nó được liên kết ở trên cùng.
HolyGeometry

2
@Zmaster Trình biên dịch sẽ coi hai loại trả về mờ là khác nhau ngay cả khi việc triển khai cho cả hai trả về cùng một loại cụ thể. Nói cách khác, loại bê tông cụ thể được chọn được ẩn khỏi người gọi. (Tôi đã có ý định mở rộng ở nửa sau của câu trả lời của mình để làm cho những điều như thế này rõ ràng hơn một chút, nhưng vẫn chưa hoàn thành nó).
Hamish

52

Câu trả lời khác làm tốt công việc giải thích khía cạnh kỹ thuật của sometừ khóa mới nhưng câu trả lời này sẽ cố gắng dễ dàng giải thích tại sao .


Giả sử tôi có một giao thức Động vật và tôi muốn so sánh nếu hai động vật là anh em ruột:

protocol Animal {
    func isSibling(_ animal: Self) -> Bool
}

Cách này chỉ có ý nghĩa để so sánh nếu hai con vật là anh em ruột nếu chúng là cùng một loại động vật.


Bây giờ hãy để tôi tạo một ví dụ về một con vật chỉ để tham khảo

class Dog: Animal {
    func isSibling(_ animal: Dog) -> Bool {
        return true // doesn't really matter implementation of this
    }
}

Con đường không có some T

Bây giờ hãy nói rằng tôi có một chức năng trả lại một con vật từ một "gia đình".

func animalFromAnimalFamily() -> Animal {
    return myDog // myDog is just some random variable of type `Dog`
}

Lưu ý: hàm này sẽ không thực sự biên dịch. Điều này là do trước khi tính năng 'some' được thêm vào, bạn không thể trả về loại giao thức nếu giao thức sử dụng 'Self' hoặc generic . Nhưng hãy nói rằng bạn có thể ... giả vờ điều này phát sóng myDog thành loại động vật trừu tượng, hãy xem điều gì xảy ra

Bây giờ vấn đề là nếu tôi cố gắng làm điều này:

let animal1: Animal = animalFromAnimalFamily()
let animal2: Animal = animalFromAnimalFamily()

animal1.isSibling(animal2) // error

Điều này sẽ ném một lỗi .

Tại sao? Lý do là, khi bạn gọi animal1.isSibling(animal2)Swift không biết liệu động vật là chó, mèo hay bất cứ thứ gì. Theo như Swift biết, animal1animal2có thể là loài động vật không liên quan . Vì chúng ta không thể so sánh động vật thuộc các loại khác nhau (xem ở trên). Điều này sẽ lỗi

Làm thế nào để some Tgiải quyết vấn đề này

Hãy viết lại chức năng trước đó:

func animalFromAnimalFamily() -> some Animal {
    return myDog
}
let animal1 = animalFromAnimalFamily()
let animal2 = animalFromAnimalFamily()

animal1.isSibling(animal2)

animal1animal2không Animal , nhưng họ là lớp học mà cụ Animal .

Điều này cho phép bạn làm bây giờ là khi bạn gọi animal1.isSibling(animal2), Swift biết điều đó animal1animal2cùng loại.

Vì vậy, cách tôi muốn nghĩ về nó:

some Tcho Swift biết cách triển khai Tđang được sử dụng nhưng người dùng của lớp thì không.

(Từ chối trách nhiệm tự quảng cáo) Tôi đã viết một bài đăng blog đi sâu hơn một chút (ví dụ tương tự như ở đây) về tính năng mới này


2
Vì vậy, ý tưởng của bạn là người gọi có thể lợi dụng thực tế là hai cuộc gọi đến hàm trả về cùng một loại mặc dù người gọi không biết đó là loại gì?
matt

1
@matt về cơ bản là yup. Khái niệm tương tự khi được sử dụng với các trường, v.v ... Người gọi được bảo đảm rằng kiểu trả về sẽ luôn là cùng loại nhưng không tiết lộ chính xác loại đó là gì.
Hạ cấp

@Downgoat cảm ơn bạn rất nhiều vì bài viết và câu trả lời hoàn hảo. Theo tôi hiểu sometrong kiểu trả về hoạt động như ràng buộc đối với phần thân của hàm. Vì vậy, someyêu cầu chỉ trả lại một loại bê tông trong toàn bộ cơ thể chức năng. Ví dụ: nếu có return randomDogthì tất cả các lợi nhuận khác phải chỉ hoạt động với Dog. Tất cả các lợi ích đến từ ràng buộc này: tính sẵn có animal1.isSibling(animal2)và lợi ích của việc biên dịch func animalFromAnimalFamily() -> some Animal(bởi vì bây giờ Selfđược xác định dưới mui xe). Nó có đúng không?
Artem

5
Dòng này là tất cả những gì tôi cần, động vật1 và động vật2 không phải là Động vật, nhưng chúng là lớp thực hiện Động vật, bây giờ tất cả đều có ý nghĩa!
vào

29

Câu trả lời của Hamish khá tuyệt vời và trả lời câu hỏi từ góc độ kỹ thuật. Tôi muốn thêm một số suy nghĩ về lý do tại sao từ khóa someđược sử dụng ở vị trí đặc biệt này trong các hướng dẫn SwiftUI của Apple và lý do tại sao nên làm theo.

some không phải là một yêu cầu!

Trước hết, bạn không cần phải khai báo bodykiểu trả về là loại mờ. Bạn luôn có thể trả về loại bê tông thay vì sử dụng some View.

struct ContentView: View {
    var body: Text {
        Text("Hello World")
    }
}

Điều này sẽ biên dịch là tốt. Khi bạn nhìn vào Viewgiao diện, bạn sẽ thấy loại trả về là loại bodyđược liên kết:

public protocol View : _View {

    /// The type of view representing the body of this view.
    ///
    /// When you create a custom view, Swift infers this type from your
    /// implementation of the required `body` property.
    associatedtype Body : View

    /// Declares the content and behavior of this view.
    var body: Self.Body { get }
}

Điều này có nghĩa là bạn chỉ định loại này bằng cách chú thích thuộc bodytính với một loại cụ thể mà bạn chọn. Yêu cầu duy nhất là loại này cần phải tự thực hiện Viewgiao thức.

Đó có thể là một loại cụ thể thực hiện View, ví dụ

  • Text
  • Image
  • Circle
  • Giáo dục

hoặc một loại mờ đục thực hiện View, tức là

  • some View

Lượt xem chung

Vấn đề phát sinh khi chúng tôi cố gắng sử dụng chế độ xem ngăn xếp làm bodykiểu trả về của, như VStackhoặc HStack:

struct ContentView: View {
    var body: VStack {
        VStack {
            Text("Hello World")
            Image(systemName: "video.fill")
        }
    }
}

Điều này sẽ không được biên dịch và bạn sẽ gặp lỗi:

Tham chiếu đến loại chung 'VStack' yêu cầu đối số trong <...>

Đó là vì lượt xem ngăn xếp trong SwiftUIloại chung ! (Và điều tương tự cũng đúng với Danh sách và các kiểu xem vùng chứa khác.)

Điều đó rất có ý nghĩa bởi vì bạn có thể cắm vào bất kỳ số lượt xem thuộc bất kỳ loại nào (miễn là nó phù hợp với Viewgiao thức). Các loại bê tông của VStackcơ thể ở trên là thực sự

VStack<TupleView<(Text, Image)>>

Khi chúng ta sau đó quyết định thêm chế độ xem vào ngăn xếp, loại cụ thể của nó sẽ thay đổi. Nếu chúng ta thêm một văn bản thứ hai sau văn bản thứ nhất, chúng ta sẽ nhận được

VStack<TupleView<(Text, Text, Image)>>    

Ngay cả khi chúng tôi thực hiện một thay đổi nhỏ, một cái gì đó tinh tế như thêm một miếng đệm giữa văn bản và hình ảnh, kiểu của ngăn xếp sẽ thay đổi:

VStack<TupleView<(Text, _ModifiedContent<Spacer, _FrameLayout>, Image)>>

Từ những gì tôi có thể nói, đó là lý do tại sao Apple khuyến nghị trong các hướng dẫn của họ luôn luôn sử dụng some View, loại mờ chung nhất mà tất cả các chế độ xem đáp ứng, như bodyloại trả về. Bạn có thể thay đổi cách triển khai / bố cục của chế độ xem tùy chỉnh mà không cần thay đổi thủ công kiểu trả về mỗi lần.


Phần bổ sung:

Nếu bạn muốn có được sự hiểu biết trực quan hơn về các loại kết quả mờ, gần đây tôi đã xuất bản một bài viết có thể đáng đọc:

Cái gì mà một số người khác trong SwiftUI?


2
Điều này. Cảm ơn! Câu trả lời của Hamish rất đầy đủ, nhưng câu trả lời của bạn cho tôi biết chính xác lý do tại sao nó được sử dụng trong các ví dụ này.
Chris Marshall

Tôi thích ý tưởng của "một số". Bất kỳ ý tưởng nếu sử dụng "một số" ảnh hưởng đến thời gian biên dịch?
Chiến binh đậu phụ

@Mischa vậy làm thế nào để tạo lượt xem tổng quát? với một giao thức có chứa lượt xem ans soir các hành vi khác?
theMouk

27

Tôi nghĩ rằng tất cả những câu trả lời còn thiếu là somehữu ích chủ yếu trong một thứ như DSL (ngôn ngữ dành riêng cho tên miền) như SwiftUI hoặc thư viện / khung, sẽ có người dùng (lập trình viên khác) khác với chính bạn.

Bạn có thể sẽ không bao giờ sử dụng sometrong mã ứng dụng thông thường của mình, ngoại trừ có lẽ trong chừng mực vì nó có thể bao bọc một giao thức chung để nó có thể được sử dụng như một loại (thay vì chỉ là một ràng buộc kiểu). Những gì somelàm là để cho trình biên dịch giữ một kiến ​​thức về loại cụ thể là gì, trong khi đặt một mặt tiền siêu kiểu trước nó.

Do đó, trong SwiftUI, nơi bạn là người dùng, tất cả những gì bạn cần biết là một cái gì đó là một some View, trong khi đằng sau hậu trường, tất cả các loại hanky-panky có thể tiếp tục mà bạn được bảo vệ. Thực tế đối tượng này là một loại rất cụ thể, nhưng bạn sẽ không bao giờ cần phải nghe về nó là gì. Tuy nhiên, không giống như một giao thức, nó là một loại chính thức, bởi vì bất cứ nơi nào nó xuất hiện, nó chỉ là một mặt tiền cho một số loại đầy đủ cụ thể.

Trong phiên bản tương lai của SwiftUI, nơi bạn đang mong đợi some View, các nhà phát triển có thể thay đổi loại cơ bản của đối tượng cụ thể đó. Nhưng điều đó sẽ không phá vỡ mã của bạn, bởi vì mã của bạn không bao giờ đề cập đến loại cơ bản ở vị trí đầu tiên.

Do đó, sometrong thực tế làm cho một giao thức giống như một siêu lớp. Nó gần như là một loại đối tượng thực, mặc dù không hoàn toàn (ví dụ: khai báo phương thức của giao thức không thể trả về a some).

Vì vậy, nếu bạn định sử dụng somecho bất cứ điều gì, rất có thể là nếu bạn đang viết DSL hoặc khung / thư viện để người khác sử dụng và bạn muốn che giấu các chi tiết loại bên dưới. Điều này sẽ giúp mã của bạn đơn giản hơn cho người khác sử dụng và sẽ cho phép bạn thay đổi chi tiết triển khai mà không vi phạm mã của họ.

Tuy nhiên, bạn cũng có thể sử dụng nó trong mã của riêng bạn như một cách che chắn một vùng mã của bạn khỏi các chi tiết triển khai được chôn trong một vùng khác trong mã của bạn.


23

Các sometừ khóa từ Swift 5.1 ( nhanh chóng tiến hóa đề nghị ) được sử dụng kết hợp với một giao thức như một kiểu trả về.

Ghi chú phát hành Xcode 11 trình bày nó như thế:

Các hàm giờ đây có thể ẩn loại trả về cụ thể của chúng bằng cách khai báo các giao thức mà nó tuân thủ, thay vì chỉ định loại trả về chính xác:

func makeACollection() -> some Collection {
    return [1, 2, 3]
}

Mã gọi hàm có thể sử dụng giao diện của giao thức, nhưng không có khả năng hiển thị vào loại bên dưới. ( SE-0244 , 40538331)

Trong ví dụ trên, bạn không cần phải nói rằng bạn sẽ trả lại một Array. Điều đó cho phép bạn thậm chí trả về một loại chung chỉ phù hợp với Collection.


Cũng lưu ý lỗi này có thể xảy ra mà bạn có thể gặp phải:

Kiểu trả về 'một số' chỉ khả dụng trong iOS 13.0.0 trở lên

Điều đó có nghĩa là bạn phải sử dụng tính khả dụng để tránh sometrên iOS 12 trở về trước:

@available(iOS 13.0, *)
func makeACollection() -> some Collection {
    ...
}

1
Rất cám ơn câu trả lời tập trung này và sự cố trình biên dịch trong Xcode 11 beta
brainray

1
Bạn phải sử dụng tính khả dụng để tránh sometrên iOS 12 trở về trước. Miễn là bạn làm, bạn sẽ ổn thôi. Vấn đề chỉ là trình biên dịch không cảnh báo bạn làm điều này.
matt

2
Như bạn đã chỉ ra, mô tả ngắn gọn của Apple giải thích tất cả: Các hàm giờ đây có thể ẩn loại trả về cụ thể của chúng bằng cách khai báo giao thức nào phù hợp với nó, thay vì chỉ định loại trả về chính xác. Và sau đó mã gọi hàm có thể sử dụng giao diện giao thức. Gọn gàng rồi vài cái.
Fattie

Điều này (ẩn loại trả về cụ thể) đã có thể mà không cần sử dụng từ khóa "some". Nó không giải thích hiệu quả của việc thêm "một số" vào chữ ký phương thức.
Vince O'Sullivan

@ VinceO'Sullivan Không thể xóa sometừ khóa trong mẫu mã đã cho này trong Swift 5.0 hoặc Swift 4.2. Lỗi sẽ là: " Nghị định thư 'Bộ sưu tập' chỉ có thể được sử dụng như là một hạn chế chung bởi vì nó có tự hoặc các yêu cầu loại có liên quan "
Cœur

2

'some' có nghĩa là loại mờ đục. Trong SwiftUI, View được khai báo là giao thức

@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public protocol View {

    /// The type of view representing the body of this view.
    ///
    /// When you create a custom view, Swift infers this type from your
    /// implementation of the required `body` property.
    associatedtype Body : View

    /// Declares the content and behavior of this view.
    var body: Self.Body { get }
}

Khi bạn tạo chế độ xem của mình dưới dạng Struct, bạn tuân thủ giao thức View và thông báo rằng phần thân var sẽ trả về một cái gì đó sẽ xác nhận với Giao thức xem. Nó giống như một bản tóm tắt Giao thức chung mà bạn không phải Xác định Loại cụ thể.


2

Tôi sẽ cố gắng trả lời điều này với ví dụ thực tế rất cơ bản (đây là loại kết quả mờ đục )

Giả sử bạn có giao thức với loại liên quan và hai cấu trúc thực hiện nó:

protocol ProtocolWithAssociatedType {
    associatedtype SomeType
}

struct First: ProtocolWithAssociatedType {
    typealias SomeType = Int
}

struct Second: ProtocolWithAssociatedType {
    typealias SomeType = String
}

Trước Swift 5.1, bên dưới là bất hợp pháp vì ProtocolWithAssociatedType can only be used as a generic constraintlỗi:

func create() -> ProtocolWithAssociatedType {
    return First()
}

Nhưng trong Swift 5.1, điều này là tốt ( someđã thêm):

func create() -> some ProtocolWithAssociatedType {
    return First()
}

Trên đây là cách sử dụng thực tế, được sử dụng rộng rãi trong SwiftUI cho some View.

Nhưng có một hạn chế quan trọng - loại trả về cần phải được biết tại thời điểm biên dịch, vì vậy, bên dưới một lần nữa sẽ không có Function declares an opaque return type, but the return statements in its body do not have matching underlying typeslỗi:

func create() -> some ProtocolWithAssociatedType {
    if (1...2).randomElement() == 1 {
        return First()
    } else {
        return Second()
    }
}

0

Một trường hợp sử dụng đơn giản mà nảy ra trong tâm trí là viết các hàm chung cho các kiểu số.

/// Adds one to any decimal type
func addOne<Value: FloatingPoint>(_ x: Value) -> some FloatingPoint {
    x + 1
}

// Variables will be assigned 'some FloatingPoint' type
let double = addOne(Double.pi) // 4.141592653589793
let float = addOne(Float.pi) // 4.141593

// Still get all of the required attributes/functions by the FloatingPoint protocol
double.squareRoot() // 2.035090330572526
float.squareRoot() // 2.03509

// Be careful, however, not to combine 2 'some FloatingPoint' variables
double + double // OK 
//double + float // error

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.