เครื่องหมายอัศเจรีย์หมายถึงอะไรในภาษา Swift


518

คู่มือภาษาโปรแกรม Swiftมีตัวอย่างดังต่อไปนี้:

class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { println("\(name) is being deinitialized") }
}

class Apartment {
    let number: Int
    init(number: Int) { self.number = number }
    var tenant: Person?
    deinit { println("Apartment #\(number) is being deinitialized") }
}

var john: Person?
var number73: Apartment?

john = Person(name: "John Appleseed")
number73 = Apartment(number: 73)

//From Apple's “The Swift Programming Language” guide (https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html)

จากนั้นเมื่อกำหนดพาร์ทเมนต์ให้กับบุคคลที่พวกเขาใช้เครื่องหมายอัศเจรีย์เพื่อ "แกะตัวอย่าง":

john!.apartment = number73

การ "แกะตัวอย่าง" หมายความว่าอย่างไร ทำไมถึงจำเป็น? มันแตกต่างจากการทำสิ่งต่อไปนี้อย่างไร:

john.apartment = number73

ฉันใหม่มากสำหรับภาษาสวิฟต์ เพียงแค่พยายามลดความรู้พื้นฐานลง


ปรับปรุง:
ชิ้นส่วนใหญ่ของจิ๊กซอว์ที่ฉันหายไป (ไม่ได้ระบุไว้โดยตรงในคำตอบ - อย่างน้อยไม่ในขณะที่เขียนนี้) คือเมื่อคุณทำสิ่งต่อไปนี้:

var john: Person?

ไม่ได้หมายความว่า " johnเป็นประเภทPersonและอาจเป็นศูนย์" อย่างที่ฉันคิดไว้ ฉันเป็นเพียงความเข้าใจผิดที่PersonและPerson?การแยกประเภทอย่างสมบูรณ์ เมื่อฉันเข้าใจสิ่ง?นั้น!ความบ้าคลั่งและคำตอบที่ดีด้านล่างทั้งหมดทำให้รู้สึกได้มากกว่า

คำตอบ:


530

การ "แกะตัวอย่าง" หมายความว่าอย่างไร ทำไมถึงจำเป็น?

เท่าที่ฉันสามารถออกกำลังกายได้ (นี่เป็นสิ่งใหม่สำหรับฉันเช่นกัน) ...

คำว่า "ห่อ" หมายถึงการที่เราควรคิดว่าตัวแปรตัวเลือกเป็นของขวัญห่อในกระดาษมันวาวซึ่งอาจ (เศร้า!) เป็นที่ว่างเปล่า

เมื่อ "ห่อ" ค่าของตัวแปรทางเลือกคือ enum ที่มีค่าที่เป็นไปได้สองค่า (ค่าเล็กน้อยเช่นบูลีน) enum นี้อธิบายว่าตัวแปรเก็บค่า ( Some(T)) หรือไม่ ( None)

หากมีค่าสามารถรับได้โดย "คลาย" ตัวแปร (ได้รับTจากSome(T))

เป็นวิธีการที่john!.apartment = number73แตกต่างจากjohn.apartment = number73? (ถอดความ)

หากคุณเขียนชื่อของตัวแปรทางเลือก (เช่นข้อความjohnโดยไม่มี!) นี่หมายถึง enum ที่ "ห่อ" (บางส่วน / ไม่มี) ไม่ใช่ค่าของตัวเอง (T) ดังนั้นจึงjohnไม่ใช่ตัวอย่างของPersonและไม่มีapartmentสมาชิก:

john.apartment
// 'Person?' does not have a member named 'apartment'

Personมูลค่าที่แท้จริงสามารถเปิดผนึกได้หลายวิธี:

  • "ถูกบังคับให้คลายลง": john!(ให้Personค่าหากมีอยู่ข้อผิดพลาดรันไทม์หากเป็นศูนย์)
  • "การเชื่อมต่อเพิ่มเติม": if let p = john { println(p) }(ดำเนินการprintlnถ้ามีค่าอยู่)
  • "การเชื่อมโยงเพิ่มเติม": john?.learnAboutSwift()(ดำเนินการเมธอดการแต่งหน้านี้หากมีค่าอยู่)

ฉันเดาว่าคุณเลือกหนึ่งในวิธีเหล่านี้ในการแกะขึ้นอยู่กับว่าจะเกิดอะไรขึ้นในกรณีศูนย์และโอกาสที่จะเกิดขึ้น การออกแบบภาษานี้บังคับให้จัดการกรณี nil อย่างชัดเจนซึ่งฉันคิดว่าจะช่วยเพิ่มความปลอดภัยให้กับ Obj-C (ซึ่งง่ายต่อการลืมที่จะจัดการกับกรณีของ nil)

อัปเดต :

เครื่องหมายอัศเจรีย์ยังใช้ในไวยากรณ์สำหรับการประกาศ "Option ที่ไม่ได้ระบุไว้โดยปริยาย"

ในตัวอย่างจนถึงjohnตัวแปรได้รับการประกาศเป็นvar john:Person?และเป็นตัวเลือก หากคุณต้องการค่าจริงของตัวแปรนั้นคุณต้องแกะมันออกมาโดยใช้หนึ่งในสามวิธีดังกล่าวข้างต้น

หากมีการประกาศเป็นvar john:Person!ตัวแปรจะเป็นตัวเลือก Unwrapped Unplicitly (ดูส่วนที่มีหัวเรื่องนี้ในหนังสือของ Apple) ไม่จำเป็นต้องแกะตัวแปรชนิดนี้เมื่อเข้าถึงค่าและjohnสามารถใช้โดยไม่มีไวยากรณ์เพิ่มเติม แต่หนังสือของ Apple บอกว่า:

ไม่ควรใช้ตัวเลือกที่ยังไม่ได้เปิดใช้โดยปริยายเมื่อมีความเป็นไปได้ที่ตัวแปรจะกลายเป็นศูนย์ในภายหลัง ใช้ชนิดที่เป็นทางเลือกปกติเสมอหากคุณต้องการตรวจสอบค่าศูนย์ในระหว่างอายุการใช้งานของตัวแปร

อัปเดต 2 :

บทความ " คุณสมบัติที่น่าสนใจของสวิฟท์ " โดย Mike Ash ให้แรงจูงใจในการเลือกประเภท ฉันคิดว่ามันยอดเยี่ยมเขียนชัดเจน

อัปเดต 3 :

อีกบทความที่มีประโยชน์เกี่ยวกับการใช้ทางเลือกโดยปริยายสำหรับเครื่องหมายอัศเจรีย์: " Swift and the Last Mile " โดย Chris Adamson บทความอธิบายว่านี่เป็นมาตรการเชิงปฏิบัติโดย Apple ที่ใช้ในการประกาศประเภทที่ใช้โดยกรอบงาน Objective-C ซึ่งอาจมีศูนย์ การประกาศประเภทเป็นตัวเลือก (ใช้?) หรือไม่ได้เปิดใช้งานโดยนัย (โดยใช้!) คือ "การแลกเปลี่ยนระหว่างความปลอดภัยและความสะดวกสบาย" ในตัวอย่างที่ให้ไว้ในบทความ Apple เลือกที่จะประกาศประเภทที่ไม่ได้เปิดใช้โดยปริยายทำให้รหัสการโทรสะดวกขึ้น แต่ปลอดภัยน้อยกว่า

บางทีแอปเปิ้ลอาจใช้กรอบในอนาคตลบความไม่แน่นอนของพารามิเตอร์ที่ไม่ได้แกะ ("อาจไม่เคยไม่มี") และแทนที่พวกเขาด้วยตัวเลือก ("แน่นอนอาจเป็นศูนย์โดยเฉพาะ [หวังว่าเอกสาร!] สถานการณ์") หรือมาตรฐาน - ตัวเลือก ("ไม่มีทางไม่มี") ประกาศตามพฤติกรรมที่แน่นอนของรหัส Objective-C ของพวกเขา


ฉันไม่แน่ใจเกี่ยวกับคำอธิบายนี้ หากคุณเพียงแค่เรียกใช้รหัสโดยไม่ต้อง! มันยังคงส่งคืนค่าที่แท้จริง อาจจะ! สำหรับความเร็ว?
Richard Washington

ตกลง. ดังนั้นเอกสารพูดคุยเกี่ยวกับการใช้! เมื่อคุณรู้ว่ามันสามารถถอดได้ แต่คุณสามารถเรียกใช้โค้ดได้โดยไม่ต้องใช้มัน (เป็นตัวเลือกที่ออกมาสำหรับรายการของคุณ - โดยปริยายการคลาย) และไม่ต้องตรวจสอบก่อน คุณคืนค่าหรือศูนย์ถ้าไม่มี แต่ถ้าคุณรู้แน่ ๆ ว่ามันไม่ได้ใช้แล้ว! ...... แต่ฉันก็ยังไม่เห็นว่าทำไมคุณถึงทำเช่นนี้?
ริชาร์ดวอชิงตัน

2
สวัสดี @RichardWashington - ฉันได้เพิ่มการอัปเดตสำหรับคำตอบของฉันซึ่งหวังว่าจะได้อธิบายบางอย่าง
แอชลีย์

อัปเดต 3 เป็นสิ่งที่ฉันกำลังมองหา ก่อนที่จะอ่านฉันคิดว่า Apple กำลังโกหกเมื่อพวกเขาส่งคืน NSURLCredential! ซึ่งอาจเป็นศูนย์
Golden Thumb

ขอบคุณสำหรับคำตอบที่ยอดเยี่ยม @Ashley หลังจากอ่านคำตอบนี้และตัวอย่างรหัสสวิฟท์ของแอปเปิ้ลแล้วฉันคิดว่าในเรื่องความปลอดภัยและความสามารถในการผลิตโดยปกติแล้วมันจะดีที่สุดที่จะปลอดภัยกว่า ข้อยกเว้นที่น่าสังเกตที่ฉันพบคือเมื่อ Apple ใช้การบังคับให้คลายองค์ประกอบองค์ประกอบ UI ซึ่งสมเหตุสมผลเนื่องจากประการแรกองค์ประกอบ UI มักจะเป็นตัวเลือกเมื่อเกี่ยวข้องกับกระดานเรื่องราว ไม่เคยเป็นศูนย์เว้นแต่ว่าพวกเขามีมุมมองควบคุมเป็นศูนย์ซึ่งในกรณีนี้การอภิปรายหาก moot
Mihir

127

นี่คือสิ่งที่ฉันคิดว่าแตกต่าง:

var john: Person?

หมายถึง john สามารถเป็นศูนย์

john?.apartment = number73

คอมไพเลอร์จะตีความบรรทัดนี้เป็น:

if john != nil {
    john.apartment = number73
}

ในขณะที่

john!.apartment = number73

คอมไพเลอร์จะตีความบรรทัดนี้เป็นเพียง:

john.apartment = number73

ดังนั้นการใช้! จะแกะคำสั่ง if และทำให้มันทำงานได้เร็วขึ้น แต่ถ้า john เป็นศูนย์แล้วจะเกิดข้อผิดพลาดรันไทม์

ดังนั้นการห่อที่นี่ไม่ได้หมายความว่ามันถูกห่อหน่วยความจำ แต่มันก็หมายถึงมันห่อด้วยรหัสในกรณีนี้มันถูกห่อด้วยคำสั่ง if และเนื่องจาก Apple ให้ความสำคัญกับประสิทธิภาพในการใช้งานจริงพวกเขาต้องการให้คุณ ทำให้แอปของคุณทำงานด้วยประสิทธิภาพที่ดีที่สุด

ปรับปรุง:

กลับไปที่คำตอบนี้หลังจาก 4 ปีเพราะฉันได้รับชื่อเสียงมากที่สุดจาก Stackoverflow :) ฉันเข้าใจความหมายของการคลายในเวลานั้นเล็กน้อย หลังจาก 4 ปีฉันเชื่อว่าความหมายของการคลายที่นี่คือการขยายรหัสจากรูปแบบกะทัดรัดดั้งเดิม นอกจากนี้ยังหมายถึงการลบความคลุมเครือรอบ ๆ วัตถุนั้นเนื่องจากเราไม่แน่ใจว่าคำจำกัดความของวัตถุนั้นเป็นศูนย์หรือไม่ เช่นเดียวกับคำตอบของแอชลีย์เหนือคิดว่ามันเป็นของขวัญที่ไม่มีอะไรในนั้น แต่ฉันยังคงคิดว่าการคลายออกคือการคลายรหัสและไม่ใช้การถอดหน่วยความจำเหมือนกับการใช้ enum


9
ในสนามเด็กเล่นของฉัน john.apartment = number73 ไม่ได้รวบรวมคุณต้องระบุ john? .apartment = number73
Chuck Pinkert

2
@ChuckPinkert ถูกต้องบรรทัดที่ 4 ควรแก้ไขให้ john? .apartment = number73 แต่คำตอบที่ดี!
บรูซ

john.apartment = number73 แสดงข้อผิดพลาด: ค่าของประเภทตัวเลือก 'บุคคล?' ไม่ได้แกะ: คุณตั้งใจจะใช้ '!' หรือ '?'?
เดอร์แมน

4
การคลายออกนั้นไม่ได้มีประสิทธิภาพอะไรเลย "ไม่มีการตรวจสอบ" จะต้องทำที่รันไทม์ความแตกต่างเพียงอย่างเดียวคือข้อผิดพลาดรันไทม์จะถูกโยนในกรณีที่ไม่มีค่าอยู่ในตัวเลือก
madidier

67

TL; DR

เครื่องหมายอัศเจรีย์หมายถึงอะไรในภาษา Swift

เครื่องหมายอัศเจรีย์พูดอย่างมีประสิทธิภาพ“ ฉันรู้ว่าตัวเลือกนี้มีค่าอย่างแน่นอน โปรดใช้มัน” สิ่งนี้เป็นที่รู้จักกันในชื่อบังคับให้แกะของคุณค่าของทางเลือก:

ตัวอย่าง

let possibleString: String? = "An optional string."
print(possibleString!) // requires an exclamation mark to access its value
// prints "An optional string."

let assumedString: String! = "An implicitly unwrapped optional string."
print(assumedString)  // no exclamation mark is needed to access its value
// prints "An implicitly unwrapped optional string."

ที่มา: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_399


11
คำตอบของคุณดีมากเพราะฉันเข้าใจว่าเกิดอะไรขึ้นตอนนี้ สิ่งที่ฉันไม่เข้าใจก็คือทำไมตัวเลือกที่ยังไม่ได้เปิดใช้โดยนัยมีอยู่ เหตุใดจึงสร้างสิ่งที่กำหนดเป็นสตริงทางเลือกที่ไม่ได้เปิดใช้งานโดยปริยายแทนที่จะเป็นประเภทสตริงปกติ การใช้งานของพวกเขาหลังจากนั้นจะเหมือนกัน ฉันพลาดอะไรไป
pachun

ดูเหมือนจะไม่เป็นความจริงอีกต่อไป ในสวิฟท์ 5 repl ถ้าผมทำlet f: String! = "hello"แล้วprint(f)ผลลัพธ์คือแทนเพียงOptional("hello") "hello"
numbermaniac

37

ถ้า john เป็นตัวเลือก var (ประกาศอย่างนี้)

var john: Person?

ถ้าเป็นไปได้ที่ john จะไม่มีค่า (ใน ObjC parlance, ค่า nil)

เครื่องหมายอัศเจรีย์โดยทั่วไปบอกคอมไพเลอร์ "ฉันรู้ว่านี่มีค่าคุณไม่จำเป็นต้องทดสอบมัน" หากคุณไม่ต้องการใช้งานคุณสามารถทดสอบได้ตามเงื่อนไข:

if let otherPerson = john {
    otherPerson.apartment = number73
}

การตกแต่งภายในของสิ่งนี้จะประเมินเฉพาะถ้า john มีค่า


4
ขอบคุณสำหรับการตอบสนองตอนนี้ฉันเข้าใจสิ่งที่เครื่องหมายอัศเจรีย์พูดว่าฉันยังคงพยายามที่จะล้อมหัวของฉันทำไม ... คุณบอกว่ามันบอกคอมไพเลอร์ "ฉันรู้ว่านี่มีค่าคุณไม่จำเป็นต้องทดสอบ มัน". มันจะซื้ออะไรให้ฉันบ้างเมื่อคอมไพเลอร์ไม่ได้ทำการทดสอบ หากไม่มีเครื่องหมายอัศเจรีย์คอมไพเลอร์จะโยนข้อผิดพลาด (ฉันไม่มีสภาพแวดล้อม แต่ฉันสามารถทดสอบ Swift ได้หรือไม่) คือ ! จำเป็น 100% สำหรับ vars เสริมหรือไม่? ถ้าเป็นเช่นนั้นทำไมแอปเปิลจึงใส่ใจกับมันแทนที่จะทำให้มันขาด ! หมายความว่า "ฉันรู้ว่านี่มีค่าคุณไม่จำเป็นต้องทำการทดสอบ"
ทรอย

"เป็นคอมไพเลอร์ที่จะส่งข้อผิดพลาด" - ไม่มันยังทำงานได้ดีคืนค่าตามที่คาดไว้ ฉันไม่ได้รับสิ่งนี้ คือ ! เพื่อความเร็วเมื่อคุณแน่ใจ
Richard Washington

ในความเป็นจริงในภายหลังเอกสารพูดคุยเกี่ยวกับตัวเลือกที่ยังไม่ได้เปิดใช้โดยนัยโดยใช้ตัวอย่างด้านล่าง: “let possibleString: String? = "An optional string." println(possibleString!) // requires an exclamation mark to access its value // prints "An optional string.” แต่มันใช้งานได้ดีโดยไม่มี! มีบางอย่างแปลก ๆ ที่นี่
ริชาร์ดวอชิงตัน

3
@RichardWashington คุณสับสนด้วยเหตุผลที่ดี! ตัวอย่างในเอกสารกำลังละทิ้งบางสิ่งและทำให้เข้าใจผิดเพราะสิ่งที่พวกเขาทำคือใช้ println เห็นได้ชัดว่ามีอย่างน้อยสองสามกรณีที่ไม่จำเป็นต้องยกเลิกการซื้อตัวเลือก หนึ่งคือเมื่อใช้ println อีกอย่างคือเมื่อใช้การแก้ไขสตริง ดังนั้นอาจจะมีการแก้ไข println และสายอักขระภายใต้ฝาครอบ? บางทีใครบางคนอาจมีความเข้าใจในเรื่องนี้มากกว่านี้ การดูคำจำกัดความของส่วนหัว Xcode6 Beta ไม่ได้เปิดเผยอะไรเลยเกี่ยวกับเวทมนต์นี้
mbeaty

ใช่ฉันเข้าใจJohn?และJohnเป็นสองประเภทที่แตกต่างกัน หนึ่งในนั้นคือบุคคลประเภทที่เป็นตัวเลือกและคนประเภทอื่น ๆ บุคคลที่ไม่จำเป็นต้องถอดออกก่อนจึงจะสามารถนำบุคคลออกไปได้ แต่อย่างที่คุณพูดสิ่งนี้ดูเหมือนจะเกิดขึ้นอย่างน้อยในสถานการณ์เหล่านี้โดยไม่ต้องทำอะไรเลย ดูเหมือนว่าจะทำให้! ซ้ำซาก เว้นแต่! เป็นทางเลือกเสมอ แต่สิ่งที่แนะนำให้ทำเพื่อรวบรวมข้อผิดพลาดของเวลาคอมไพล์ ชนิดของการกำหนด vars / อนุญาตให้กับบางประเภทสามารถระบุได้อย่างชัดเจนlet John: Person = ...แต่สามารถอนุมานlet John = ...ได้
ริชาร์ดวอชิงตัน

27

มุมมองภาพใหญ่เพื่อเพิ่มคำตอบที่เป็นประโยชน์ แต่มีรายละเอียดมากขึ้น:

ใน Swift จุดอัศเจรีย์ปรากฏขึ้นในหลายบริบท:

  • บังคับให้แกะออก: let name = nameLabel!.text
  • ตัวเลือกที่ไม่ได้เปิดใช้โดยนัย: var logo: UIImageView!
  • บังคับให้หล่อ: logo.image = thing as! UIImage
  • ข้อยกเว้นที่ไม่สามารถจัดการได้: try! NSJSONSerialization.JSONObjectWithData(data, [])

สิ่งเหล่านี้ทุกคนมีโครงสร้างภาษาที่แตกต่างกันและมีความหมายแตกต่างกัน แต่พวกเขามีสามสิ่งสำคัญที่เหมือนกัน:

1. เครื่องหมายอัศเจรีย์หลีกเลี่ยงการตรวจสอบความปลอดภัยเวลารวบรวมของ Swift

เมื่อคุณใช้!ในสวิฟท์, คุณจะได้เป็นหลักบอกว่า“Hey, คอมไพเลอร์, ฉันรู้ว่าคุณคิดว่ามีข้อผิดพลาดที่อาจเกิดขึ้นที่นี่ แต่ฉันรู้ว่าด้วยความเชื่อมั่นรวมว่ามันไม่เคยจะ.”

ไม่ใช่รหัสที่ถูกต้องทั้งหมดที่ใส่ลงในกล่องระบบรวบรวมเวลาของ Swift หรือการตรวจสอบประเภทคงที่ของภาษาใด ๆสำหรับเรื่องนั้น มีสถานการณ์ที่คุณสามารถพิสูจน์ได้อย่างมีเหตุผลว่าข้อผิดพลาดจะไม่เกิดขึ้น แต่คุณไม่สามารถพิสูจน์ได้กับคอมไพเลอร์จะคอมไพเลอร์นั่นเป็นเหตุผลที่นักออกแบบของ Swift เพิ่มคุณสมบัติเหล่านี้ในตอนแรก

อย่างไรก็ตามเมื่อใดก็ตามที่คุณใช้!คุณจะต้องมีเส้นทางการกู้คืนสำหรับข้อผิดพลาดซึ่งหมายความว่า ...

2. เครื่องหมายอัศเจรีย์อาจล่ม

เครื่องหมายอัศเจรีย์ยังพูดว่า“เฮ้ Swift ผมเพื่อให้แน่ใจว่าข้อผิดพลาดนี้ไม่สามารถเกิดขึ้นว่ามันจะดีกว่าสำหรับคุณที่จะผิดพลาดของแอปทั้งหมดของฉันมากกว่าที่เป็นอยู่สำหรับผมที่จะรหัสเส้นทางสำหรับการกู้คืนมัน.”

นั่นเป็นการยืนยันที่อันตราย มันอาจเป็นรหัสที่ถูกต้อง: ในรหัสภารกิจสำคัญที่คุณคิดอย่างหนักเกี่ยวกับค่าคงที่ของรหัสของคุณอาจเป็นไปได้ว่าผลลัพธ์ปลอมจะเลวร้ายยิ่งกว่าความผิดพลาด

อย่างไรก็ตามเมื่อฉันเห็น!ในป่ามันไม่ค่อยได้ใช้อย่างมีเหตุผล “ ค่านี้เป็นทางเลือกและฉันไม่ได้คิดหนักเกินไปเกี่ยวกับสาเหตุที่อาจเป็นศูนย์หรือวิธีจัดการสถานการณ์อย่างเหมาะสม แต่การเพิ่ม!ทำให้คอมไพล์…ดังนั้นรหัสของฉันถูกต้องใช่ไหม”

ระวังความเย่อหยิ่งของเครื่องหมายอัศเจรีย์ แทน…

3. เครื่องหมายอัศเจรีย์ถูกใช้อย่างประหยัดที่สุด

โครงสร้างเหล่านี้ทุกตัว!มี?คู่ที่บังคับให้คุณจัดการกับข้อผิดพลาด / ไม่มีกรณี:

  • การเปิดเงื่อนไขแบบมีเงื่อนไข: if let name = nameLabel?.text { ... }
  • optionals: var logo: UIImageView?
  • เงื่อนไขปลดเปลื้อง: logo.image = thing as? UIImage
  • ข้อยกเว้น Nil-on-Fail: try? NSJSONSerialization.JSONObjectWithData(data, [])

หากคุณถูกล่อลวงให้ใช้งาน!คุณควรพิจารณาอย่างรอบคอบเสมอว่าทำไมคุณไม่ใช้งาน?แทน การหยุดโปรแกรมของคุณเป็นตัวเลือกที่ดีที่สุดหากการ!ทำงานล้มเหลว เหตุใดค่าจึงเป็นตัวเลือก / พร้อมใช้งาน

มีเส้นทางการกู้คืนที่สมเหตุสมผลรหัสของคุณอาจใช้ในกรณีที่ไม่มี / ข้อผิดพลาด? ถ้าเป็นเช่นนั้นรหัสมัน

หากมันไม่สามารถเป็นศูนย์ได้หากข้อผิดพลาดไม่สามารถเกิดขึ้นได้มีวิธีที่เหมาะสมในการปรับตรรกะของคุณใหม่เพื่อให้คอมไพเลอร์รู้หรือไม่? ถ้าเป็นเช่นนั้นทำมัน; รหัสของคุณจะมีข้อผิดพลาดน้อยลง

มีบางครั้งที่ไม่มีวิธีที่เหมาะสมในการจัดการข้อผิดพลาดและเพียงละเว้นข้อผิดพลาด - และดำเนินการกับข้อมูลที่ไม่ถูกต้อง - จะเลวร้ายยิ่งกว่าการล่ม เหล่านี้เป็นเวลาที่จะใช้กำลังเปิดออก

ฉันค้นหา codebase ทั้งหมดเป็นระยะ!และตรวจสอบการใช้งานทุกครั้ง ประเพณีน้อยมากที่ยืนขึ้นเพื่อตรวจสอบข้อเท็จจริง (จากการเขียนนี้กรอบงาน Siesta ทั้งหมดมีสอง อินสแตนซ์ของมันอย่างแน่นอน)

ไม่ได้หมายความว่าคุณไม่ควรใช้!รหัสของคุณ แต่คุณควรใช้อย่างระมัดระวังและไม่ทำให้เป็นตัวเลือกเริ่มต้น


func isSubscriptionActive(receiptData: NSDictionary?) -> Bool { if(receiptData == nil) { return false; } return (hasValidTrial(receiptData!) || isNotExpired(receiptData!)) && isNotCancelled(receiptData!) } ได้รับ 3. มีวิธีที่ดีกว่าในการเขียนหรือไม่?
jenson-button-event

คุณสามารถพูดได้func isSubscriptionActive(receiptData: NSDictionary?) -> Bool { guard let nonNilReceiptData = receiptData else { return false} return (hasValidTrial(nonNilReceiptData) || isNotExpired(nonNilReceiptData)) && isNotCancelled(nonNilReceiptData) }
rkgibson2

เครื่องหมายอัศเจรีย์ไม่หลีกเลี่ยงการตรวจสอบความปลอดภัย คุณได้รับการรับประกันความผิดพลาดหากตัวเลือกเป็นศูนย์ ตัวเลือกจะถูกตรวจสอบเสมอ มันเป็นวิธีที่โหดร้ายมากในการตรวจสอบความปลอดภัย
gnasher729

@ gnasher729 ในฐานะที่เป็นคำตอบมันจะหลีกเลี่ยงการตรวจสอบความปลอดภัยเวลาคอมไพล์ในความโปรดปรานของความล้มเหลวรันไทม์ที่ปลอดภัย
Paul Cantrell

24

johnvarเป็นตัวเลือก ดังนั้นสามารถมีnilค่า เพื่อให้แน่ใจว่าไม่มีค่าใด ๆ ให้ใช้ a !ที่ท้ายvarชื่อ

จากเอกสาร

“ เมื่อคุณแน่ใจว่าตัวเลือกนั้นมีค่าอยู่แล้วคุณสามารถเข้าถึงมูลค่าพื้นฐานได้โดยเพิ่มเครื่องหมายอัศเจรีย์ (!) ที่ท้ายชื่อตัวเลือก เครื่องหมายอัศเจรีย์พูดอย่างมีประสิทธิภาพ“ ฉันรู้ว่าตัวเลือกนี้มีค่าอย่างแน่นอน โปรดใช้มัน”

อีกวิธีในการตรวจสอบค่าที่ไม่เป็นศูนย์คือ

    if let j = json {
        // do something with j
    }

1
ใช่ฉันเคยเห็นว่าในเอกสาร แต่มันก็ดูเหมือนว่าไม่จำเป็น ... เช่นเดียวกับฉันjohn.apartment = number73ยังบอกว่า "ฉันรู้ว่าตัวเลือกนี้มีค่าแน่นอนโปรดใช้มัน" ...
Troy

6
ใช่แล้ว แต่ประเด็นก็คือโดยค่าเริ่มต้น Swift จะพยายามตรวจจับข้อผิดพลาดในเวลารวบรวม หากคุณรู้หรือคิดว่าคุณรู้ว่าตัวแปรนี้ไม่มีศูนย์คุณสามารถลบเครื่องหมายถูกออกโดยใช้เครื่องหมายอัศเจรีย์
lassej

16

นี่คือตัวอย่างบางส่วน:

var name:String = "Hello World"
var word:String?

ในกรณีที่wordเป็นค่าตัวเลือก หมายความว่าอาจมีหรือไม่มีค่า

word = name 

ที่นี่nameมีค่าเพื่อให้เราสามารถกำหนดได้

var cow:String = nil
var dog:String!

ในกรณีที่dogแกะห่ออย่างรุนแรงหมายความว่าต้องมีค่า

dog = cow

แอปพลิเคชันจะทำงานล้มเหลวเนื่องจากเราได้รับมอบหมายnilให้เปิดเครื่อง


1
var c:Int = nilจะได้รับ: "Nil ไม่สามารถเริ่มต้นประเภท 'int'" ที่ระบุ
Asususer

15

ในกรณีนี้...

var John: บุคคล!

หมายความว่าในตอนแรกจอห์นจะมีค่าเป็นศูนย์จะถูกตั้งค่าและเมื่อตั้งค่าแล้วจะไม่ถูกนำมาใช้อีกครั้ง ดังนั้นเพื่อความสะดวกฉันสามารถใช้ไวยากรณ์ที่ง่ายขึ้นสำหรับการเข้าถึง var ที่ไม่จำเป็นเนื่องจากนี่คือ "ทางเลือกที่ไม่ได้เปิดใช้งานโดยนัย"


1
ขอบคุณ. ฉันพบลิงก์ต่อไปนี้ซึ่งอธิบายสิ่งนี้ ประเภทนี้เรียกว่า "ตัวเลือกที่ยังไม่ได้เปิดโดยปริยาย" stackoverflow.com/questions/24122601/…
Kaydell

5

หากคุณมาจากภาษาตระกูล C คุณจะนึกถึง "ตัวชี้ไปยังวัตถุประเภท X ซึ่งอาจเป็นที่อยู่หน่วยความจำ 0 (NULL)" และหากคุณมาจากภาษาที่พิมพ์แบบไดนามิกคุณจะ กำลังคิด "วัตถุที่อาจเป็นประเภท X แต่อาจเป็นประเภทที่ไม่ได้กำหนด" สิ่งเหล่านี้ไม่ถูกต้องจริงแม้ว่าจะอยู่ในวงเวียนคนแรกที่เข้ามาใกล้

วิธีที่คุณควรคิดว่ามันเป็นราวกับว่ามันเป็นวัตถุ:

struct Optional<T> {
   var isNil:Boolean
   var realObject:T
}

เมื่อคุณกำลังทดสอบค่าตัวเลือกของคุณกับfoo == nilมันจริงๆกลับมาfoo.isNilและเมื่อคุณบอกว่าfoo!มันกลับมาด้วยการยืนยันว่าfoo.realObject foo.isNil == falseมันเป็นเรื่องสำคัญที่จะต้องทราบเรื่องนี้เพราะถ้าfooเป็นจริงแล้วเมื่อคุณfoo!นั่นเป็นข้อผิดพลาดรันไทม์ดังนั้นโดยทั่วไปคุณจะต้องการใช้การอนุญาตแบบมีเงื่อนไขแทนเว้นแต่คุณจะแน่ใจว่าค่าจะไม่เป็นศูนย์ กลอุบายชนิดนี้หมายความว่าสามารถพิมพ์ภาษาได้อย่างมากโดยไม่บังคับให้คุณทดสอบว่ามีค่าใด ๆ หรือไม่

ในทางปฏิบัติมันไม่ได้ทำงานอย่างนั้นเพราะคอมไพเลอร์ทำงาน ในระดับสูงมีประเภทFoo?ที่แยกจากกันFooและป้องกัน funcs ที่ยอมรับประเภทFooจากการรับค่าศูนย์ แต่ในระดับต่ำค่าตัวเลือกไม่ได้เป็นวัตถุจริงเพราะมันไม่มีคุณสมบัติหรือวิธีการ; เป็นไปได้ว่าในความเป็นจริงมันเป็นตัวชี้ซึ่งอาจเป็น NULL (0) พร้อมกับการทดสอบที่เหมาะสมเมื่อบังคับให้เปิด - ปิด

มีสถานการณ์อื่นที่คุณเห็นเครื่องหมายอัศเจรีย์อยู่ในประเภทเช่นเดียวกับใน:

func foo(bar: String!) {
    print(bar)
}

สิ่งนี้เทียบเท่ากับการยอมรับตัวเลือกที่มีการบังคับให้แกะห่อนั่นคือ:

func foo(bar: String?) {
    print(bar!)
}

คุณสามารถใช้วิธีนี้เพื่อมีวิธีที่ยอมรับค่าทางเทคนิค แต่จะมีข้อผิดพลาดรันไทม์หากเป็นศูนย์ ในเวอร์ชั่นปัจจุบันของ Swift สิ่งนี้เห็นได้ชัดว่าเป็นการข้ามการยืนยันที่ไม่ใช่ตัวอักษรดังนั้นคุณจะมีข้อผิดพลาดระดับต่ำแทน โดยทั่วไปแล้วไม่ใช่ความคิดที่ดี แต่อาจมีประโยชน์เมื่อทำการแปลงรหัสจากภาษาอื่น


3

ตัว! หมายความว่าคุณกำลังบังคับเปิดวัตถุ! ดังต่อไปนี้ ข้อมูลเพิ่มเติมสามารถพบได้ในเอกสารแอปเปิ้ลซึ่งสามารถพบได้ที่นี่: https://developer.apple.com/library/ios/documentation/swift/conceptual/Swift_Programming_Language/TheBasics.html


3

หากคุณคุ้นเคยกับ C # นี่เป็นเหมือนประเภทที่ใช้งานได้ซึ่งประกาศด้วยเครื่องหมายคำถาม:

Person? thisPerson;

และเครื่องหมายอัศเจรีย์ในกรณีนี้เทียบเท่ากับการเข้าถึงคุณสมบัติ. Value ของประเภท nullable ดังนี้:

thisPerson.Value

2

ในวัตถุประสงค์ตัวแปร C ที่ไม่มีค่าเท่ากับ 'ไม่มี' (มันเป็นไปได้ที่จะใช้ค่า 'ศูนย์' เช่นเดียวกับ 0 และเท็จ) ดังนั้นจึงเป็นไปได้ที่จะใช้ตัวแปรในงบตามเงื่อนไข (ตัวแปรที่มีค่าเหมือนกันกับ 'TRUE 'และผู้ที่ไม่มีค่าเท่ากับ' FALSE ')

Swift ให้ความปลอดภัยประเภทโดยการให้ 'ค่าเสริม' ie มันป้องกันข้อผิดพลาดที่เกิดขึ้นจากการกำหนดตัวแปรประเภทต่าง ๆ

ดังนั้นใน Swift จะสามารถให้บริการบูลีนได้ในงบที่มีเงื่อนไข

var hw = "Hello World"

ที่นี่แม้ว่า 'hw' เป็นสตริงมันไม่สามารถใช้ในคำสั่ง if เหมือนในวัตถุประสงค์ C

//This is an error

if hw

 {..}

เพื่อที่จะต้องสร้างเป็น

var nhw : String? = "Hello World"

//This is correct

if nhw

 {..}

2

ตัว! ในตอนท้ายของวัตถุบอกว่าวัตถุนั้นเป็นตัวเลือกและจะทำการแกะถ้ามันสามารถคืนค่าเป็นศูนย์ได้ ซึ่งมักใช้เพื่อดักข้อผิดพลาดที่อาจทำให้โปรแกรมขัดข้อง


2

ในระยะสั้น (!): หลังจากที่คุณประกาศตัวแปรและคุณมั่นใจว่าตัวแปรนั้นถือค่าอยู่

let assumedString: String! = "Some message..."
let implicitString: String = assumedString

อื่นคุณจะต้องทำเช่นนี้ในทุกค่าหลังจากผ่าน ...

let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // requires an exclamation mark

1

จอห์นเป็นบุคคลทางเลือกซึ่งหมายความว่ามันสามารถเก็บค่าหรือเป็นศูนย์

john.apartment = number73

ใช้ถ้า john ไม่ใช่ตัวเลือก ตั้งแต่จอห์นไม่เคยเป็นศูนย์เราจึงมั่นใจได้ว่ามันจะไม่เรียกอพาร์ทเมนท์ตามมูลค่าศูนย์ ในขณะที่

john!.apartment = number73

สัญญาว่าคอมไพเลอร์ที่ john ไม่ได้เป็นศูนย์จะไม่ใส่ตัวเลือกเพื่อรับค่าของ john และเข้าถึงอพาร์ทเมนต์ของ john ใช้สิ่งนี้ถ้าคุณรู้ว่าจอห์นไม่ได้เป็นศูนย์ หากคุณเรียกใช้ตัวเลือกนี้คุณจะได้รับข้อผิดพลาดรันไทม์

เอกสารประกอบมีตัวอย่างที่ดีสำหรับการใช้สิ่งนี้โดยที่ convertNumber เป็นตัวเลือก

if convertedNumber {
    println("\(possibleNumber) has an integer value of \(convertedNumber!)")
} else {
    println("\(possibleNumber) could not be converted to an integer")
}

คุณกำลังบอกว่าถ้าจอห์นเป็นศูนย์และฉันไปjohn.apartment = number73ว่าจะไม่ส่งผลให้เกิดข้อผิดพลาดถ้าฉันใส่ '!' หลังจากจอห์น
ทรอย

ถ้า john เป็นตัวเลือกคุณต้องใช้เครื่องหมายอัศเจรีย์เพื่อเข้าถึงคุณสมบัติของมันเนื่องจากคอมไพเลอร์ต้องรู้ว่าไม่ใช่ศูนย์ หากไม่ใช่ตัวเลือกคุณจะไม่สามารถใช้เครื่องหมายอัศเจรีย์ได้
Connor

1
ถ้าฉันต้องใช้เครื่องหมายอัศเจรีย์สำหรับตัวเลือกเสริมทั้งหมดทำไมแอปเปิลถึงต้องกังวลกับมันแทนที่จะทำอย่างนั้นการที่ไม่มีเครื่องหมายอัศเจรีย์หมายถึงสิ่งเดียวกัน ดูเหมือนว่าไม่จำเป็นต้องมี bloat ... หรือมีกรณีที่เหมาะสมที่จะไม่ใช้เครื่องหมายอัศเจรีย์พร้อมตัวเลือก var หรือไม่?
ทรอย

คุณใช้เครื่องหมายอัศเจรีย์เมื่อคุณต้องการตัวเลือกที่จะไม่เป็นศูนย์ เช่นเดียวกับในกรณีที่มีการเข้าถึงคุณสมบัติของจอห์น คุณสามารถทำอะไรเช่น var jack: คน = john โดยที่แจ็คยังเป็นตัวเลือกหรือ var jack: Person = john! โดยที่แจ็คคือบุคคลและไม่เป็นศูนย์
Connor

ใช่ แต่ในตัวอย่างดั้งเดิมความจริงที่ว่าฉันไม่ชอบการjohnบอกเลิกตัวเลือกบอกคอมไพเลอร์ที่ฉันต้องการให้ไม่ใช่ศูนย์หรือไม่ ... และในvar jack: Person = john!ตัวอย่างของคุณไม่ขาดหรือไม่ หลังจากคนบอกคอมไพเลอร์ว่าคุณjohnจะต้องไม่ใช่ศูนย์? โดยรวมแล้ว!ดูเหมือนว่าดูเหมือนจะซ้ำซ้อน ... มันยังคงรู้สึกเหมือนว่าฉันขาดอะไรบางอย่างใน "ทำไม" ส่วนหนึ่งของ!...
ทรอย

1

หากต้องการใส่เพียงอย่างเดียวเครื่องหมายอัศเจรีย์หมายถึงตัวเลือกที่ไม่ได้เปิดใช้งาน ทางเลือกคือตัวแปรที่สามารถมีค่าหรือไม่ - เพื่อให้คุณสามารถตรวจสอบว่าตัวแปรว่างเปล่าโดยใช้คำสั่ง if let ตามที่แสดงที่นี่แล้วบังคับให้แกะออก หากคุณบังคับให้แกะตัวเลือกที่ว่างเปล่าโปรแกรมของคุณจะพังดังนั้นโปรดระวัง! มีการประกาศตัวเลือกโดยการใส่เครื่องหมายคำถามท้ายการกำหนดอย่างชัดเจนให้กับตัวแปรตัวอย่างเช่นฉันสามารถเขียน:

var optionalExample: String?

ตัวแปรนี้ไม่มีค่า ถ้าฉันจะแกะมันออกมาโปรแกรมจะพังและ Xcode จะบอกคุณว่าคุณพยายามแกะตัวเลือกที่มีค่าเป็นศูนย์

หวังว่าจะช่วย


1

ในคำง่าย ๆ

การใช้เครื่องหมายอัศเจรีย์ระบุว่าตัวแปรจะต้องประกอบด้วยค่าที่ไม่ใช่ศูนย์ (ซึ่งไม่เป็นศูนย์)


1

เรื่องราวทั้งหมดเริ่มต้นด้วยคุณสมบัติของ swift ที่เรียกว่า vars เสริม เหล่านี้คือ vars ซึ่งอาจมีค่าหรืออาจไม่มีค่า โดยทั่วไปแล้ว swift ไม่อนุญาตให้เราใช้ตัวแปรที่ไม่ได้กำหนดค่าเริ่มต้นเนื่องจากอาจทำให้เกิดข้อผิดพลาดหรือสาเหตุที่ไม่คาดคิดรวมถึงเซิร์ฟเวอร์ที่สำรองไว้สำหรับแบ็คดอร์ ดังนั้นเพื่อประกาศตัวแปรที่ไม่ได้กำหนดค่าเริ่มต้นเราจึงใช้ '?' เมื่อมีการประกาศตัวแปรเพื่อใช้เป็นส่วนหนึ่งของนิพจน์บางตัวที่ต้องแกะพวกเขาออกก่อนการใช้งานการเปิดใช้งานเป็นการดำเนินการซึ่งค่าของตัวแปรถูกค้นพบสิ่งนี้นำไปใช้กับวัตถุ หากคุณพยายามใช้พวกเขาคุณจะมีข้อผิดพลาดในการรวบรวมเวลา หากต้องการแกะตัวแปรซึ่งเป็น var ที่ไม่จำเป็นให้เลือกเครื่องหมายอัศเจรีย์ "!" ถูกนำมาใช้.

ขณะนี้มีบางครั้งที่คุณรู้ว่าตัวแปรตัวเลือกดังกล่าวจะได้รับการกำหนดค่าโดยระบบตัวอย่างหรือโปรแกรมของคุณเอง แต่บางครั้งในภายหลังเช่นช่องเสียบ UI ในสถานการณ์เช่นนั้นแทนที่จะประกาศตัวแปรทางเลือกโดยใช้เครื่องหมายคำถาม "?" เราใช้ "!".

ดังนั้นระบบจะรู้ว่าตัวแปรนี้ซึ่งประกาศด้วย "!" เป็นตัวเลือกในขณะนี้และไม่มีค่า แต่จะได้รับค่าในภายหลังในช่วงอายุการใช้งาน

เครื่องหมายอัศเจรีย์จะมีลักษณะที่แตกต่างกันสองประการคือ 1. ในการประกาศตัวแปรซึ่งจะเป็นทางเลือกและจะได้รับค่าในภายหลังอย่างแน่นอน 2. ในการแกะตัวแปรทางเลือกก่อนที่จะใช้มันในนิพจน์

คำอธิบายข้างต้นหลีกเลี่ยงสิ่งทางเทคนิคมากเกินไปฉันหวังว่า


1

หากคุณใช้เป็นตัวเลือกจะเป็นการยกเลิกการเลือกและดูว่ามีบางอย่างอยู่หรือไม่ หากคุณใช้มันในคำสั่ง if-else เป็นรหัสสำหรับไม่ ตัวอย่างเช่น,

if (myNumber != 3){
 // if myNumber is NOT 3 do whatever is inside these brackets.
)

1

ตัวแปรทางเลือกอาจมีค่าหรืออาจจะไม่

กรณีที่ 1: var myVar:String? = "Something"

กรณีที่ 2: var myVar:String? = nil

ตอนนี้ถ้าคุณถาม myVar! คุณกำลังบอกคอมไพเลอร์ให้คืนค่าในกรณีที่ 1 มันจะกลับมา "Something"

ในกรณีที่ 2 มันจะผิดพลาด

ความหมาย! เครื่องหมายจะบังคับให้คอมไพเลอร์ส่งคืนค่าแม้ว่าจะไม่มีอยู่ก็ตาม thats ทำไมชื่อกองทัพแกะ


@Moritz ฉันไม่รู้เหมือนกันเหรอ? ไม่สามารถตอบคำถามได้หรือไม่? ฉันกำลังก่อให้เกิดปัญหาใด ๆ หรือมีอะไรผิดปกติในคำตอบของฉันหรือไม่? ฉันไม่เข้าใจทำไมคุณถึงลงการตอบรับอย่างถูกต้อง? ฉันพยายามตอบตามความเข้าใจในแนวคิด ฉันคิดว่าบางคนจะเป็นประโยชน์สำหรับคำอธิบายที่ชัดเจนและง่าย
Ashish Pisey

@ Moritz ทีนี้นี่เป็นสิ่งที่สร้างสรรค์ คุณควรบอกการแก้ไขนี้ให้ฉันตั้งแต่แรกถ้านี่คือเหตุผล ขอบคุณสำหรับความคิดเห็น. ฉันแก้ไขมันแล้ว
Ashish Pisey

0
Simple the Optional variable allows nil to be stored.

var str : String? = nil

str = "Data"

To convert Optional to the Specific DataType, We unwrap the variable using the keyword "!"

func get(message : String){
   return
}

get(message : str!)  // Unwapped to pass as String

1
กรุณาอย่าเขียนคำตอบที่ไม่ได้เพิ่มอะไรที่ยังไม่ได้ครอบคลุมโดยคำตอบก่อนหน้า
Dalija Prasnikar

-1

ถามตัวเอง

  • ประเภทนี้person?มีapartmentสมาชิก / สถานที่ให้บริการหรือไม่? หรือ
  • ประเภทนี้personมีapartmentสมาชิก / สถานที่ให้บริการหรือไม่?

หากคุณไม่สามารถตอบคำถามนี้ให้อ่านต่อไป:

เพื่อให้เข้าใจถึงคุณอาจต้องระดับซุปเปอร์พื้นฐานของความเข้าใจของGenerics ดูที่นี่ มีหลายสิ่งใน Swift ที่เขียนขึ้นโดยใช้ Generics ตัวเลือกรวม

โค้ดข้างล่างนี้ได้รับการให้บริการจากวิดีโอนี้ Stanford ขอแนะนำให้คุณดู 5 นาทีแรก

ตัวเลือกเป็น enum ที่มีเพียง 2 กรณี

enum Optional<T>{
    case None
    case Some(T)
}

let x: String? = nil //actually means:

let x = Optional<String>.None

let x :String? = "hello" //actually means:

let x = Optional<String>.Some("hello")

var y = x! // actually means:

switch x {
case .Some(let value): y = value
case .None: // Raise an exception
}

ตัวเลือกผูกพัน:

let x:String? = something
if let y = x {
    // do something with y
}
//Actually means:

switch x{
case .Some(let y): print)(y) // or whatever else you like using 
case .None: break
}

เมื่อคุณพูดว่าvar john: Person?คุณหมายถึงเช่น:

enum Optional<Person>{
case .None
case .Some(Person)
}

enum ด้านบนมีคุณสมบัติชื่อapartmentหรือไม่? คุณเห็นมันทุกที่หรือไม่ มันไม่ได้มีเลย! อย่างไรก็ตามถ้าคุณแกะมันออกperson!แล้วทำเช่นนั้นคุณสามารถ ... สิ่งที่ทำภายใต้ประทุนคือ:Optional<Person>.Some(Person(name: "John Appleseed"))


คุณได้กำหนดไว้var john: Personแทนvar john: Person?แล้วคุณจะไม่จำเป็นต้องใช้อีกต่อไป!เพราะPersonตัวมันเองมีสมาชิกapartment


ในฐานะที่เป็นการอภิปรายในอนาคตเกี่ยวกับสาเหตุ!ที่ไม่แนะนำให้ใช้ในการแกะผลิตภัณฑ์โปรดดูคำถาม & คำตอบนี้


2
การใช้สไลด์จริงด้านบนอาจเป็นการละเมิดลิขสิทธิ์: "... มหาวิทยาลัยสแตนฟอร์ดเก็บลิขสิทธิ์เนื้อหาทั้งหมดในคอลเลกชัน iTunes U ของเรา" จากhttp://itunes.stanford.edu คำตอบของคุณอาจดีกว่าคือเนื้อหาที่คุณเรียนรู้จากหลักสูตรที่คุณรับรู้ที่จะตอบคำถามนี้ (และแทนที่จะใช้สไลด์แทนที่จะพูดส่วนที่เกี่ยวข้องในรูปแบบรหัสโดยมีการอ้างอิงตามธรรมชาติ)
dfri

2
อาร์กิวเมนต์ของคุณคือpopulum โฆษณา argumentum อย่างไรก็ตามฉันไม่เชื่อว่า Stanford จะมาที่นี่และบังคับใช้สิทธิ์ DMCAแต่จะดีกว่าเสมอหากคำตอบของคุณอยู่ในคำพูดของคุณโดยอ้างอิงจากแหล่งข้อมูลที่เป็นทางการ / ถูกต้องและไม่ใช่ในรูปแบบของการคัดลอกแหล่งข้อมูลเหล่านั้นทั้งหมด โดยเฉพาะอย่างยิ่งเมื่อเราพูดถึงสไลด์ที่มีลิขสิทธิ์: อีกครั้งดีกว่าที่จะอ้างถึงเนื้อหาของสไลด์ในบล็อกรหัส
dfri

1
เมตาโพสต์ที่ฉันเชื่อมโยงเพื่ออธิบายวิธีการของ SO: โพสต์เช่นนี้จะไม่ถูกลบโดยธรรมชาติหากผู้ใช้บางรายรายงานว่าเป็นการละเมิดลิขสิทธิ์: หากเป็นตัวแทนของ Stanford เท่านั้น กำลังจะมาที่นี่และเนื่องจากการโพสต์ที่จะถูกลบจึงจำเป็นต้องบังคับใช้ ดังนั้นผมเขียน" ผมไม่เชื่อว่าสแตนฟอจะมาที่นี่และบังคับใช้สิทธิ DMCA ..." ประเด็นของฉันข้างต้นคือฉันเชื่อว่านี่น่าจะเป็นการละเมิดลิขสิทธิ์ (ซึ่งฉันเชื่อว่าผิด) แต่โดยธรรมชาติจะไม่มีใครบังคับใช้สิ่งนี้ ...
dfri

1
แต่สิ่งนี้นอกเหนือจากการโพสต์คำถามหรือคำตอบที่มีภาพของรหัสเป็นกำลังใจด้วยเหตุผลหลายประการ เพื่อสรุป: ฉันได้พยายามชี้ให้เห็นความคิดเห็นเหล่านี้ว่าฉันเชื่อว่าคำตอบนี้ในรูปแบบปัจจุบันไม่ดีเท่าที่ควรเนื่องจากเหตุผลสองประการที่สำคัญ (ภาพนิ่งที่มีลิขสิทธิ์ภาพของรหัส) โดยธรรมชาติแล้วไม่มีใครรวมถึงตัวฉันเองจะทำอะไรเกี่ยวกับเรื่องนี้ฉันแค่ชี้ให้เราใช้เป็นข้อมูลอ้างอิงในอนาคต ตกลง iTunes U! :)
dfri

2
@dfri ลบภาพ
ฮั
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.