• בלוג
  • היום למדתי להיזהר מהפונקציה contains בקלוז'ר

היום למדתי להיזהר מהפונקציה contains בקלוז'ר

20/09/2024

האתגר הכי גדול עבורי עם קלוז'ר הוא חוסר העקביות של השפה, או שאולי יש לה איזשהו הגיון פנימי שאני לא מבין. הקיטור היום הוא על הפונקציות contains? ו keys.

הפונקציה keys בקלוז'ר מקבלת מפה ומחזירה את המפתחות שלה. זה קל:

user=> (keys {:a 10 :b 20 })
(:a :b)

ברור שאי אפשר להשתמש ב keys על וקטור, כי אין לו מפתחות. קלוז'ר היא הרי לא JavaScript והיא לא חושבת שמפתחות של מערך זה האינדקסים שלו. זה מה שקורה אם מנסים:

user=> (keys ["a" "b" "c"])
Error printing return value (ClassCastException) at clojure.lang.APersistentMap$KeySeq/first (APersistentMap.java:168).
class java.lang.String cannot be cast to class java.util.Map$Entry (java.lang.String and java.util.Map$Entry are in module java.base of loader 'bootstrap')

בהתבסס על ההגיון הזה הלכתי לשחק עם הפונקציה contains? בעבודה על מפה, הפונקציה contains? בודקת אם ערך מסוים הוא מפתח במפה. עד פה הכל גם הגיוני:

user=> (contains? {:a 10 :b 20} :a)
true

בגלל ש keys לא עובדת על מערכים, חשבתי שגם contains? לא אמורה לעבוד על מערכים, וקצת הופתעתי לגלות שהיא דווקא עובדת ואפילו לפעמים צודקת:

user=> (contains? [1 2 3] 2)
true

אבל זה היה רק מוקש. למעשה contains? על מערכים בקלוז'ר בודקת אם הפרמטר שהיא קיבלה הוא אינדקס במערך - ולא ערך. הדוגמה הקודמת עבדה רק במקרה. הנה כמה דוגמאות יותר טובות:

user=> (contains? [1 2 3] 0)
true
user=> (contains? [1 2 3] 3)
false
user=> (contains? ['a' 'b' 'c'] 0)
true
user=> (contains? ['a' 'b' 'c'] 'a')
false
user=> (contains? ['a' 'b' 'c'] 9)
false

ונשארתי עם השאלה - אם האינדקסים של מערך הם המפתחות שלו, למה keys לא מחזירה את רשימת האינדקסים? ואם הם לא מפתחות, למה contains? בודקת אם ערך שהיא קיבלה הוא אינדקס חוקי במערך?